chenqunfeng / Blog

个人技术记录博客
6 stars 1 forks source link

Javascript 模块化演变过程 #3

Open chenqunfeng opened 7 years ago

chenqunfeng commented 7 years ago

匿名函数

CommonJS

官方说明

CommonJS是服务器端模块的规范,Node.js采用了这个规范。 根据CommonJS规范,一个单独的文件就是一个模块。加载模块使用require方法,该方法读取一个文件并执行,最后返回文件内部的exports对象。

原理

  1. 路径分析
  2. 文件定位
  3. 编译执行

分析

路径分析

文件定位

编译执行

AMD

CMD

UMD

browserify

官方说明

让用户可以使用node的require()的方式来组织浏览器端的 Javascript 代码,然后browserify会递归解析所有require()的调用来生成最后的打包文件。

与CommonJS的差异

因为浏览器的原因,它无法做到跟服务器那样可以以很快的速度同步读取一份文件,所以browserify需要提前打包依赖,也就是预编译、预处理过程。

原理

  1. 分析入口文件代码中require()的调用并生成AST文件
  2. 根据AST文件找到每个模块require的模块名
  3. 根据每个模块的依赖关系,生成一个依赖字典
  4. 传入依赖字典以及自己实现的export和require函数,生成用于执行的bundle.js

分析

browserify b.js > bundle.js

1、分析入口文件代码中require()的调用并生成AST文件
// b.js
var sayHello = require('./a.js');
sayHello('CQF');

生成AST文件:可以使用esprima实现该过程。

2、根据AST文件找到每个模块require的模块名

提取require:可以使用node-detective实现该过程。

3、根据每个模块的依赖关系,生成一个依赖字典

做完以上步骤以后,你便可以得到以下形式的依赖字典

{
  1:[function(require,module,exports){
    var sayHello = function(name) {
      console.log('hello' + ' ' + name);
    };

    module.exports = sayHello;
  },{}
  ],
  2:[function(require,module,exports){
    var a = 1;
    if (a) {
      var sayHello = require('./a.js');
      sayHello('CQF');
    }
  },
  {"./a.js":1}
  ]}
4、传入依赖字典以及自己实现的export和require函数,生成用于执行的bundle.js

在生成的bundle.js中,我们可以发现一段实现require,module,exports三个关键字的代码,将第三步生成的依赖字段作为参数传入以后,便是可以在浏览器中运行的完整的bundle.js。

ES6