CJS、ESM、UMD模块化标准
1. CommonJS
node.js的实现中采用了CommonJS标准的一部分,并在其基础上进行了一些调整
使用方式
使用require
和exports
或者module.exports
进行模块的导入导出
1 | // node.js为了简化操作,有var exports = module.exports |
特点
1.CJS 模块输出的是值的拷贝
2.一个文件就是一个模块,name.js中的作用域是影响不到index.js的。
1 | // name.js |
原因
1 | // 当node在执行模块中的代码时,它会首先在代码的最顶部,添加如下代码 |
3.以同步的方式加载模块,模块加载顺序即在代码中的顺序,每个require语句会短暂阻塞代码的运行,知道模块加载完毕。不过这个加载不是通过网络加载,而是从内存或者文件系统中加载,所以这个过程很快。也导致CJS不适合浏览器
4.有缓存机制,已经被引入过的模块,不会再一次引入
1 | // 由使用方式小节可知,其实模块会有一个module对象,而这个module对象会存放模块的信息 |
5.循环引用下的行为
将上文练习的b.js文件修改成下面这样:
1 | const a = require('./a.js'); |
a.js文件内容如下:
1 | const b = require('./b.js'); |
执行node a.js
,打印出
1 | {} b中拿到的a |
首先执行a.js,a中引用了b,所以b开始执行,b中又引用了a,此时a没有任何导出内容,所以b拿到的a是一个空对象。
修改a.js文件内容如下:
1 | exports.a1 = '111'; |
可以看见在导入b之前先导出了a1,执行node a.js
,打印的内容是:
1 | { a1: '111' } b中拿到的a |
说明在b中导入a的时候的拿到的是那个时刻a中已经导出的内容,如果没有导出,就会拿到一个空对象。
exports 是动态执行的,具体 require 能获取到的值,取决于模块的运行情况
2.AMD
Asynchronous Module Definition(异步模块规范),最老的方式之一,专为浏览器而设计,RequireJS实现了AMD API
使用方式
用define
方法定义模块,用require
导出模块
1 | define( |
特点
- 可以定义具名模块,也可以定义匿名模块。具名模块通过开发者定义的名字加载,匿名模块隐式的以文件名加载
- require调用会发送一个请求来下载模块
- 异步加载,只有在回调函数里才能获取新拿到的API
- 可以在代码的任何地方使用require加载另一个模块
3. ESM
与CJS和AMD不同,es6的模块是静态的,
使用方式
用import
和import()
进行导入,用export
、export default
进行导出
特点
1.ES6 模块输出的是值的引用
1 | // lib.js |
2.会动态的从被加载的模块中取值
1 | // m1.js |
3.导入的模块变量是只读的,如果修改就会报错
1 | // lib.js |
4.循环引用下的行为
1 | // a.mjs |
执行a.mjs
,在a.mjs
中引擎发现它加载了b.mjs
,因此会优先执行b.mjs
,在b.mjs
中发现它又加载了a.mjs
,形成循环引用,已知a.mjs
输入了foo
接口,这时不会去执行a.mjs
,而是认为这个接口已经存在了,继续往下执行,执行到第三行console.log(foo)
的时候,才发现这个接口根本没定义,因此报错。
与CJS不同的是,ESM可以利用函数提升来解决上述问题,在b.mjs
运行的时候,已经有foo
的定义了
让我们看另一个例子
1 | // a.mjs |
执行a.mjs
,因为import具有提升效果,所以在b.mjs
中的第二行就会报ReferenceError: Cannot access 'a_done' before initialization
的错误,同样的例子CJS由于没有提升,则可以获取到a_done
为false
ps:babel编译过后上述例子不会报错
4.UMD
UMD:Universal Module Definition(通用模块规范)是由社区想出来的一种整合了CommonJS和AMD两个模块定义规范的方法。
UMD模块的顶端通常都会有如下的代码,用来判断模块加载器环境。
1 | (function (root, factory) { |
参考
《深入浅出Webpack》
https://es6.ruanyifeng.com/#docs/module-loader
https://juejin.cn/post/6870141103958589454
https://juejin.cn/post/6844903861166014478
CJS、ESM、UMD模块化标准