NodeJS 中的 esModule 与 commonJS
NodeJS 从 v14 版本开始正式支持解析 esModule,通过扩展 .mjs
或 .cjs
后缀,可以将 js 文件解析为 esModule 和 commonJS。
此外,也可以在文件目录下单独设置一个 package.json
,声明 { "type": "module }
,默认在当前目录下使用 esModule 规范,进行模块解析。
那么,Node 当中的 esModule 和 commonJS 有哪些不同呢?
模块加载
在 commonJS 中,require()
的执行是同步的。它在调用后并不会返回一个 Promise 或者回调函数,而是直接从磁盘或者网络中读取资源(可能涉及到磁盘或网络的 I/O),并立即执行脚本中的内容,返回最后将 module.exports
的值。
在 esModule 中,模块的加载是异步的。首先,模块解析器(module loader
)会对脚本进行静态解析,无需执行脚本中的内容,就可以分析出所有的 import
和 export
调用。在解析过程中,解析器可以快速地检查脚本引入或导出模块时的语法错误,并及时抛出异常。
esModule 的解析器会异步的下载与解析代码中引入的脚本,递归的分析模块间的引用关系,构建出完成的「模块依赖图谱」(module graph
)。当解析完成后,对应的脚本以及它所依赖的脚本,就可以等待执行了。
所有的脚本都是并行下载的,并且按照引入顺序执行。
路径解析
在 esModule 中使用 import
时,必须完成声明文件路径,包括文件扩展名,如 './src/index.js'
。
在 node v14 版本中,使用 esModule 必须遵守 file:
协议,即 URL-based paths
。
环境变量
commonJS 中的环境变量/对象,包括 require
, exports
, module.exports
, __filename
, __dirname
,在 esModule 中都是无法使用的。
如果需要在 esModule 使用 require
,可以通过 module.createRequire()
。
如果需要使用 __filename
, __dirname
,可以通过 import.meta.url
进行读取。
require.cache
require.cache
esModule 中无法使用 require.cache
,而 commonJS 会缓存引入模块的相关信息。每次 require 模块后,commonJS 会缓存对应的模块,从 cache 中删除某个模块,那么下一次 require 会重新加载这个模块。
commonJS 中 require.cache
的数据结构如下:
参考
Last updated
Was this helpful?