模块化的发展历程
按照诞生时间的先后顺序
- CommonJs,2009年1月
- AMD
Asynchronous Module Definition
, 2011年2月 - CMD
Common Module Definition
, 2011年4月后 - UMD
Universal Module Definition
, 2014年9月 - ESM
EcmaScript Module
, 2016年5月
CommonJs 模块规范
第一阶段: Modules/1.0, 产物 browserify
第二阶段: Modules/Async, 诞生了 Modules/AsynchronousDefinition
规范
第三阶段: Modules/2.0,基于 CommonJS 规范的实现:BravoJS
- 运行时加载,一个文件就是一个模块
- 更适合服务端,node.js 采用了这个规范
- 同步加载模块,不支持异步
- 使用
require/exports
关键字
AMD
AMD
是 RequireJS 在推广过程中对模块定义的规范化产出。
- 一种基于模块的异步加载的js代码机制
- 通过延迟和按需加载来解决各个模块之间的依赖关系,
依赖前置、提前执行
-
define
关键字用于定义模块,require
关键字用来引用模块
CMD
CMD
是阿里的玉伯(王保平)在借鉴了CommonJs 和 AMD 方案后写出的 SeaJS 在推广过程中对模块定义的规范化产出。
- 与AMD大体相同,也是异步加载
- 特点是
依赖就近、延迟执行
AMD 和 CMD 的依赖和执行时机的比较
AMD:
// a.js
define(function () {
console.log('init a.js');
return {
getFun: function () {
return 'I am a';
}
};
});
// b.js
define(function () {
console.log('init b.js');
return {
getFun: function () {
return 'I am b';
}
};
});
// index.js
define(function (require) {
var a = require('./a');
console.log(a.getFun());
var b = require('./b');
console.log(b.getFun());
});
<script src="https://cdn.bootcss.com/require.js/2.3.6/require.min.js"></script>
<script>
requirejs(['index']);
</script>
// 输出结果如下
// init a.js
// init b.js
// I am a
// I am b
CMD:
// a.js
define(function (require, exports, module) {
console.log('init a');
exports.getFun = function () {
return 'I am a';
}
});
// b.js
define(function (require, exports, module) {
console.log('init b');
exports.getFun = function () {
return 'I am b';
}
});
// index.js
define(function(require, exports, module) {
var a = require('./a'); //在需要时申明
console.log(a.getFun());
var b = require('./b'); //在需要时申明
console.log(b.getFun());
});
<script src="https://cdn.bootcss.com/seajs/3.0.3/sea.js"></script>
<script>
seajs.use('./index.js')
</script>
// 输出
// init a
// I am a
// init b
// I am b
UMD
- 前后端跨平台的解决方案
- 兼容 AMD 和 CommonJS 的规范,并支持传统的声明全局变量的方式
- 先判断是否支持 AMD(define是否存在),存在则使用 AMD 方式加载模块
- 再判断是否支持 Node.js 模块格式( exports 是否存在),存在则使用 Node.js 模块格式
- 前两个都不存在,则将模块公开到全局( window 或 global )
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['jquery', 'underscore'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS-like
module.exports = factory(require('jquery'), require('underscore'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.jQuery, root._);
}
}(this, function ($, _) {
// methods
function a(){}; // private because it's not returned (see below)
function b(){}; // public because it's returned
function c(){}; // public because it's returned
// exposed public methods
return {
b: b,
c: c
}
}));
ESM
2015年6月,ES6/ES2015 正式通过决议,从语言层面提出的一种模块化标准。
- 编译时加载,模块加载从入口文件开始,最终生成完整的模块实例关系图,过程包含:
- 构建:查找,下载,然后把所有文件解析成 module record。
- 实例化:为模块分配内存空间,依照导入,导出语句把模块指向对应内存地址。
- 运行:把内存空间填充为真实值。
- node V8.5.0+ 对其进行了支持
- 使用
import / export
关键字
参考
https://github.com/amdjs/amdjs-api/wiki/AMD
CMD 模块定义规范
Sea.js 与 RequireJS 的异同
https://www.davidbcalhoun.com/2014/what-is-amd-commonjs-and-umd/
https://dev.to/iggredible/what-the-heck-are-cjs-amd-umd-and-esm-ikm
编程时间简史