模块化

模块规范

  • ESM: 编译时导入(静态),导入的是值的引用(只读),所以模块导出值的改变会被引用方感知(循环引用情况下,只要保证执行至使用值的地方时,已经有对应的值即可);可用import()实现动态导入。目前普遍做法是利用打包工具(webpack、rollup等)把使用了ESM源码编译成浏览器可识别的JS语法。若在支持ESM的浏览器中,直接使用script标签<sript type="module" src="entry.js"/>即可

  • CJS: 运行时导入(动态),导入的是值的拷贝,所以模块导出值的改变不会影响到引用方(循环引用时,需保证取值时就有对应的值)。可以在条件语句中引入模块,可以引入动态路径的模块。NodeJS中默认使用的模块化方案

  • UMD:降级兼容方案,CJS => AMD => 挂载到全局(window/global),一般由打包工具导出

  • AMD:依赖前置,提前加载,如requireJS

  • CMD:依赖就近,需要时加载,如seaJS

差异

主流模块化方案是 esm 和 cjs。

从规范上看,二者最根本的差异是建立模块关联的阶段不同:编译时(esm) vs 运行时(cjs),从而导致了一系列表现上的差异:能否嵌套在条件语句、是否支持动态路径、循环引用时的取值等。

相同之处是,同一程序中(“程序”对于 node 是一个进程,对于 web 是一个 spa),引用的模块都是按“单例”处理,即同一公共模块被不同业务模块引用时,实际激活的模块内存是同一份,即业务模块对其内部数据的改动会影响其他业务模块。