zoukankan      html  css  js  c++  java
  • 走向Node与Webpack 之路

    走向Node与Webpack 之路 - CommonJS 模块化

    1. 参考资料

    JavaScript 标准参考教程(alpha)

    CommonJS规范(推荐 - 阮一峰写的)

    官方网站 (看半天,不知道干啥!)

    CommonJS 是什么 ? (有些晕)


    2. 基本环境

    • node v4.5.0
    • npm v4.2.0

    这里基本环境安装配置就不说了,自己查找资料。

    使用webstrom ,使用 node 记得enable ,写相关命令的时候,才会提醒显示: 
    如图:我的是已经打开的

    这里写图片描述


    3. 认识

    无论是node应用模块,还是webpack 配置 ,均是采用CommonJS模块化规范。

    Example :

    example.js

    /**
     * Created by yuan on 2/21/2017.
     */
    var x = 1;
    var addX = function (value) {
        return value + x;
    }
    
    module.exports.x = x; #对外提供值
    module.exports.addX = addX; #对外提供函数

    example-test.js

    /**
     * Created by yuan on 2/21/2017.
     */
    var example = require('./example.js') #加载模块
    console.log(example.x) #调用value
    console.log(example.addX(12)); #调用函数

    执行 : node xxx.js 执行 js 文件

    D:webworkspacewebpack-democommond>node example1-test.js
    1
    13

    规范:

    • 每个js 文件就是一个模块,有自己的作用域 ;
    • 每个js 文件定义的函数,变量,类都是私有的;
    • 每个模块的运行,不会污染全局作用域 ;
    • 每个模块可以多次加载,但只会在第一次加载时运行一次,然后结果就缓存了;重新运行模块,需要清除缓存;
    • 所有模块的加载顺序不定,按照被使用的顺序加载;
    • require : 加载模块
    • module.exports : 对外提供接口

    3.module

    所有的模块都是一个module对象,代表当前模块

    Example : 
    引入jquery , 打印当前module ;

    • npm install jquery -g : 安装jquery
    D:webworkspacewebpack-democommond>npm install jquery -g
    C:UsersyuanAppDataRoaming
    pm
    `-- jquery@3.1.1
    • 配置 package.json dependencies 依赖
     "dependencies": {
        "jquery": "^3.1.1",
      }
    • example.js
    /**
     * Created by yuan on 2/21/2017.
     */
    var jquery= require('jquery');
    exports.$ = jquery;
    console.log(module);
    • 执行
    D:webworkspacewebpack-democommond>node example2.js
    Module {
      id: '.', #模块识别,通常是模块的绝对路径文件名
      exports: { '$': [Function] },#模块对外输出的接口
      parent: null, # 返回对象,表示调用该模块的模块
      filename: 'D:\webworkspace\webpack-demo\commond\example2.js', # 绝对路径的模块名
      loaded: false, # 表示是否加载完成
      children: # 表示该模块依赖的其他模块
       [ Module {
           id: 'D:\webworkspace\webpack-demo\node_modules\jquery\dist\jquery.js',
           exports: [Function],
           parent: [Circular],
           filename: 'D:\webworkspace\webpack-demo\node_modules\jquery\dist\jquery.js',
           loaded: true,
           children: [],
           paths: [Object] } ],
      paths:
       [ 'D:\webworkspace\webpack-demo\commond\node_modules',
         'D:\webworkspace\webpack-demo\node_modules',
         'D:\webworkspace\node_modules',
         'D:\node_modules' ] }
    

    (1)认识module

    • id : 模块识别,通常是模块的绝对路径文件名
    • exports : 模块对外输出的接口
    • parent : 返回对象,表示调用该模块的模块
    • filename : 绝对路径的模块名
    • loaded : 表示是否加载完成
    • children : 表示该模块依赖的其他模块

    (2)module.exports

    module.exports 当前模块对外输出的接口,对外提供变量;在每个模块中默认实现了

    var exports=module.exports;

    Example 1 :

    /**
     * 返回x平方与y平方和
     * @param x
     * @param y
     * @returns {number}
     */
    function add(x, y) {
        return x * x + y * y;
    }
    // exports.add = add; // 对外提供add函数
    // module.exports.add = add; //对外提供add函数 

    结果:

    上面两种写法,实现的效果是一样的;建议使用 module.exports 来做,我觉得代码清晰。

    Example 2 :

    //ok
    exports.hello = function () {
        console.log('hello node!')
    };
    
    //error1 : 该exports 赋值 就和 module.exports 没有了联系!
    exports = function (x) {
        console.log(x);
    };
    //error2 :
    module.exports = 'hello commonJS';

    结果:

    注意: 不可以对exports 或 module.exports 直接赋值,不然exports 就和 module 本身的exports 没有关系了。


    4. require

    require 加载模块文件: 读入并执行javascript 文件 ,返回该module.exports对象

    (1)简单的加载

    Example :

    example.js

    var sayHi = function (name) {
        console.log(name + ' say hi !');
        console.log(require.main===module); #false
    };
    
    module.exports.sayhi = sayHi;

    example-test.js

    var say = require('./example.js'); #加载上面的exmple.js
    console.log(say.sayhi('labelnet'));
    console.log(require.main === module); #true

    执行

    D:webworkspacewebpack-democommond>node example4-test.js
    labelnet say hi !
    false
    undefined
    true
    

    总结: 

    require.main === module 可以判断模块是直接执行的还是被调用执行的,如果直接执行返回true , 被调用的返回false;

    (2)require 加载规则

    进行加载时,默认后缀名时 .js , 也就是说 require('./example4.js') 和 require('./example4') 效果实现一样的。

    参数格式:

    参数格式决定了不同路径寻找模块文件

    • “/” 开头 , 绝对路径加载
     require('/yuan/dist/example.js')
    • “.” 开头 , 相对路径加载,比如 同一目录加载
    require('./example4')
    require('./example4.js')
    • “文件名称”, 加载默认提供的核心模块,package.json 以 配置的模块,当然node_modules以安装的工程
    require('jquery')

    (3)缓存

    每个模块被加载时,只执行一次,其余的都去缓存中获取;

    requrie.cache

    Example :

    require('./example');
    require('./example').message = 'hello js';
    console.log(require('./example').message);

    上面代码,加载了三次example, 第二次添加message 变量,第三次打印message变量; 
    结果:

    D:webworkspacewebpack-democommond>node example5-test.js
    hello js

    说明 第三次的结果是从缓存中获取的;

    删除缓存

    删除缓存,必须知道缓存模块的绝对路径,才可以删除; 
    基本格式 :

    delete require.cache[模块绝对路径];

    Example :

    require('./example');
    require('./example').message = 'hello js';
    // console.log(module); //可以获取到模块的绝对路径
    delete require.cache['D:\webworkspace\webpack-demo\commond\example.js']; //删除指定模块缓存,缓存是根据绝对路径识别的!!
    
    console.log(require('./example').message);

    结果:

    D:webworkspacewebpack-democommond>node example5-test.js
    undefined

    删除全部缓存

    Object.keys(require.cache).forEach(function (key) {
        delete require.cache[key];
    });

    5. 加载机制

    (1)require 加载机制

    对外输出的值,是这个值得拷贝(复制),如果这个值内部值改变,那么对外输出的值并不改变;

    Example : 
    先打印外部值,改变内部值,再次打印外部值;

    example.js

    var value = 3;
    function add() {
        value++;
        console.log('内部 value +1 : ' + value)
    }
    
    module.exports = {
        value: value,
        add: add,
    };

    example-test.js

    /**
     * Created by yuan on 2/21/2017.
     */
    var test= require('./exapmle6');
    
    console.log('外部 value 执行1 : '+test.value);
    console.log(test.add());
    console.log('外部 value 执行2 : '+test.value);
    
    

    结果:

    D:webworkspacewebpack-democommond>node example6-test.js
    外部 value 执行1 : 3
    内部 value +1 : 4
    undefined
    外部 value 执行2 : 3

    (2)require 内部处理流程 (学习来源)

    require 不是一个全局命令,而是指向当前模块的module.require命令,而后者又调用Node的内部命令Module._load

    Module._load = function(request, parent, isMain) {
      // 1. 检查 Module._cache,是否缓存之中有指定模块
      // 2. 如果缓存之中没有,就创建一个新的Module实例
      // 3. 将它保存到缓存
      // 4. 使用 module.load() 加载指定的模块文件,
      //    读取文件内容之后,使用 module.compile() 执行文件代码
      // 5. 如果加载/解析过程报错,就从缓存删除该模块
      // 6. 返回该模块的 module.exports
    };

    上面的第4步,采用 module.compile() 执行指定模块的脚本,逻辑如下。

    Module.prototype._compile = function(content, filename) {
      // 1. 生成一个require函数,指向module.require
      // 2. 加载其他辅助方法到require
      // 3. 将文件内容放到一个函数之中,该函数可调用 require
      // 4. 执行该函数
    };

    上面的第1步和第2步,require函数及其辅助方法主要如下。

    • require(): 加载外部模块
    • require.resolve():将模块名解析到一个绝对路径
    • require.main:指向主模块
    • require.cache:指向所有缓存的模块
    • require.extensions:根据文件的后缀名,调用不同的执行函数

    一旦require函数准备完毕,整个所要加载的脚本内容,就被放到一个新的函数之中,这样可以避免污染全局环境。该函数的参数包括require、module、exports,以及其他一些参数。

    (function (exports, require, module, __filename, __dirname) {
      // YOUR CODE INJECTED HERE!
    });

    Module._compile方法是同步执行的,所以Module._load要等它执行完成,才会向用户返回module.exports的值 。

    转自:https://blog.csdn.net/LABLENET/article/details/56287947

  • 相关阅读:
    Vector Dictionary HashMap
    崩溃java (打印当前类的地址)
    colspan、rowspan的使用
    基础操作
    安装vuex-devtools插件
    在使用Vuex插件进行状态管理的步骤
    运行cnpm run dev出现错误解决办法
    在使用vue开发时,文件路径的引用(给文件起别名)
    下载脚手架vue.cli出现的问题
    什么是闭包?
  • 原文地址:https://www.cnblogs.com/mycognos/p/9277329.html
Copyright © 2011-2022 走看看