js模块发展的基本过程:
早期 -> CommonJs -> AMD -> UMD -> ESModule
早期
<script src="./module1.js"></script>
<script src="./module2.js"></script>
<script src="./module3.js"></script>
早期js没有模块化, 只是将不同代码块写在不同的js文件中进行简单的隔离.
问题:
- 所有js文件中的变量依然处于同一个全局作用域下, 就会有变量提升, 重复定义的问题
- 代码块之间有依赖关系的话,需要额外关注脚本加载的顺序
为解决上面的问题, 需要将脚本文件进行[模块化]:
- 每个模块在自己的变量作用域, 避免污染全局作用域和避免与其他模块的代码发生冲突
- 模块之间有互相导入和导出的通信方法
- 模块的加载与执行遵循一定的规范 (模块导入单例化), 保证模块之间的依赖关系.
CommonJs
CommonJs是Nodejs实现的模块化规范.
在CommonJS 规范里,每个 JS 文件就是一个 模块(module),每个模块内部可以使用require函数和
module.exports对象来对模块进行导入和导出。
//index.js
require("./moduleA");
var m = require("./moduleB");
console.log(m);
//moduleA.js
var m = require("./moduleB");
setTimeout(()=>console.log(m),1000);
//moduleB.js
var m = new Date().getTime();
module.exports m;
node 才会在解析 JS 的过程中提供⼀个 require ⽅法,这样当解析器执⾏代码时,发现有模块调⽤了 require 函数,就会通过参数找到对应模块的物理路径,通过系统调⽤从硬盘读取⽂件内容,解析这段内容最终拿到导出结果并返回。
从它的执⾏过程也能看出来 CommonJS 是⼀个 同步加载模块 的模块化规范,每当⼀个模块 require ⼀ 个⼦模块时,都会停⽌当前模块的解析直到⼦模块读取解析并加载。
AMD
受到 CommonJS 模块化规范的启发,WEB 端逐渐发展出 异步模块定义 AMD (Asynchronous module definition).
简单理解, AMD规范 约等于 CommonJs + 异步模块加载.
不同于CommonJs的同步加载模块, AMD应用场景是web开发, 为避免模块同步加载阻塞页面响应的问题, 所以AMD模块默认都是异步加载.
<script src="/require.js"></script>
// index.js
require(['moduleA', 'moduleB'], function (moduleA, moduleB) {
console.log(moduleB);
});
// moduleA.js
define(function (require) {
var m = require('moduleB');
setTimeout(() => console.log(m), 1000);
});
// moduleB.js
define(function (require) {
var m = new Date().getTime();
return m;
});
UMD
UMD(Universal Module Definition) 作为⼀种同构(强调在不同环境中运行时的不变性)的模块化解决方案出现,它能够让我们只需要在⼀个地⽅定义模块内容,并同时兼容 AMD 和 CommonJS 语法。
检测出当前的模块化规范, 然后将模块内容按对应的模块化规范语法导出即可
(function (self, factory) {
if (typeof module == 'object' && typeof module.exports == 'object') {
//当前环境是CommonJS规范环境
module.exports = factory();
} else if (typeof define === 'function' && define.amd) {
//当前环境是AMD规范环境
define(factory)
} else {
//什么环境都不是,直接挂在全局对象上
self.umdModule factory();
}
}(this, function () {
return function () {
return Math.random();
}
}));
ESModule
CommonJs/AMD 有以下特点:
- 语言上层的运行环境中实现的模块化规范
- 相互之间不能共享模块, AMD模块不能被用于node环境, CommonJs模块不能被用于浏览器环境
ES6 之后,JS 有了语⾔层⾯的模块化导入导出关键词与语法以及与之匹配的 ESModule 规范.
ESModule 与 CommonJS 和 AMD 最⼤的区别在于,ESModule 是由 JS 解释器实现,⽽后两者是在宿主环境中运⾏时实现。ESModule 导⼊实际上是在语法层⾯新增了⼀个语句,⽽ AMD 和 CommonJS 加载模块 实际上是调⽤了 require 函数。
// index.js
import './moduleA';
import m from './moduleB';
console.log(m);
// moduleA.js
import m from './moduleB';
setTimeout(()) => console.log(m), 1000);
// moduleB.js
var m = new Date().getTime();
export default m;