think of JsModule
模块导入导出的历史
JsModule 的演化经历
下面这张图可以清晰的看出,javascript module 演化的历史,由最初的 commonjs 到最终方案 esm,而现在正处于 umd -> esm 阶段.
commonjs
commonjs 的特性就是其导入不是在编译器编译时执行的,而是在代码执行时才实行的.其特性导致了两个特点: 动态导入和赋值复制.
- 动态导入.
下面这段 js 代码完美诠释了此含义,在此判断为 true 的情况下的 commonjs,才会导入 selectivizr,并实行 selectivizr 中的脚本.
1 | if(browser.desktop && browser.msie && browser.versionNumber < 9){ |
- 赋值复制.
1 | // module.js |
1 | // index.js |
上面这两段 js 代码完美诠释了此含义,其结果为:
count: 4
count: 4
可以看出 commonjs 对于导出的变量以及函数都是代码执行时直接复制其值,而不是连同引用一起导出,导致通过模块内部修改变量的值之后,在外部导入模块变量并没有发现其值发生变化.
优势和劣势.
优势:
- 导入比较灵活;
- NodeJS 模块导入导出完全采用 commonjs 模式,npm 上绝大部分的依赖库都会兼容 commonjs 模块导入导出,适用范围很广泛;
- 同步模块加载;
- 良好的团队维护,完备的社区/论坛;
劣势:
- 不支持静态分析,静态分析所带来的一系列福利不能在 commonjs 模块导入导出模式下实行;
- 不能实行异步模块加载;
amd(cmd)
amd(cmd) 的适用范围很窄,受众面也远远没有 commonjs 和 esm 广泛,因为受限于第三方库的环境依赖(无论是 SeaJS,还是 RequireJS 都需要事先下载依赖).
优势和劣势.
优势:
- 支持同步/异步模块加载,amd 近似于同步模块导入导出(与 commonjs 同步模块加载有着本质的不同),cmd 异步模块导入导出(与 esm 异步模块加载也有着本质的不同);
劣势:
- 不支持静态分析,静态分析所带来的一系列福利不能在 amd(cmd) 模块导入导出模式下实行;
- 受限于第三方库的环境依赖;
- 写法上很不友好;
- 适用范围很窄,没有类 NodeJS、npm 以及 ECMAScript 标准这种受众面很广泛的’推手’推动;
- 社区/论坛不成熟,维护一般;
umd
umd,全称: Universal Module Definition,其标准为: commonjsStrictGlobal以及returnExportsGlobal.
- commonjsStrictGlobal.
1 | // Uses CommonJS, AMD or browser globals to create a module. This example |
- returnExportsGlobal.
1 | // Uses CommonJS, AMD or browser globals to create a module. |
从源码中可以看出 umd 是对于 commonjs、Node(webpack中值枚举为commonjs2)、amd 以及 Browser globals 的并集,是实行兼容的一种模块导入导出模式.
优势和劣势.
优势:
- 兼容的这几种模块导入导出都支持同步模块加载;
- 导入比较灵活;
- 导出的类型更丰富;
劣势:
- 不支持静态分析,静态分析所带来的一系列福利也不能在 umd 模块导入导出模式下实行;
- 不能实行异步模块加载;
esm(ecmascript module)
模块导入导出的最终方案模式,也是现在 NodeJS、npm 以及 ECMAScript 标准这些受众面很广泛的’推手’主要推动的模块导入导出模式. 其导入是在编译器编译阶段,由此特性也导致了两个特点: 静态分析和赋值引用,与 commonjs 的特性与特点完全相反.
- NodeJS ESM.
混用阶段,也就是 import 配合 module.exports,require 配合 export.
注意在 import 配合 module.export 这部分,import 必须导入 module.exports 导出的模块,不能导入 exports 导出的模块,由于还是以commonjs模块导出,那么esm导入就不能实行静态分析,只能整体导入.
1 | //module.js |
1 | //index.js |
- 静态分析.
其导入是在编译器编译阶段,所以需要将所使用的模块都在所要导入文件的头部进行导入.可对其引入的值、函数或者模块可进行静态分析.
1 | //module.js |
1 | //index.js |
- 赋值引用.
1 | //module.js |
1 | //index.js |
上面这两段 js 代码与 commonjs 赋值复制部分是同一个🌰,但是执行结果却是不相同的,其结果为:
count: 4
count: 5
可以看出 esm 对于导出的变量以及函数都是编译器编译时连同引用一起导出,导致通过模块内部修改变量的值之后,在外部导入模块变量的值也发生了改变.
优势和劣势.
优势:
- 支持静态分析,静态分析所带来的一系列福利都可接收;
- 可实行异步模块加载;支持动态导入 import();
- 良好的团队维护,完备的社区/论坛;
劣势:
- 现阶段 NodeJS、npm 以及 ECMAScript 标准这些受众面很广泛的’推手’因历史、兼容、底层改动大等问题,实现的都不成熟,还需要 Webpack/Babel 等工具进行转译;