本文记录了一些
ESM 使用
以及ESM 和 CommonJS 互相引用
的知识点,假定你对 CommonJS 和 ESM 有一定的了解。 你也可以参考 阮一峰: ESM Module 的语法 和 阮一峰: ESM Module 的加载实现 获取更多信息。
较新的 NodeJS 版本(>=13.2.0)可以加载 CommonJS 和 ESM,用户需指明具体某些文件是什么模块类型。可以简单参考如下:
ESM import 常用场景
一图胜千言:
import { add } from ‘moduleA’
此时 add 是 moduleA
导出的函数 add
。
// moduleA.mjs
export function add(a, b) {
return a + b
}
import moduleA from ‘moduleA’
此时 moduleA 是 moduleA
导出的 default
, 等价于import { default as moduleA } from 'moduleA'
// moduleA.mjs
export default {
add: function(a, b) {
return a + b
}
}
import * as moduleA from ‘moduleA’
此时 moduleA 对应模块 moduleA
中的 namespace object
, 可简单理解为所有导出的变量,包括default
。
// moduleA.mjs
export function add(a, b) {
return a + b
}
export default function add(a, b) {
return a + b
}
模块类型混乱引发的异常
如果 package.json 中 type = commonjs,尝试运行 ESM 文件,会报错
如果 package.json 中 type = moudle,尝试运行 CommonJS 文件,会报错
CommonJS 文件中引用 ESM 模块
使用场景较少,此处不谈论。
ESM 文件中引用 CommonJS 模块
// tool.cjs
function add(a, b) {
return a + b
}
exports.add = add
// test.mjs
// 三种方式都可以
import { add } from './tool.cjs'
import Tool1 from './tool.cjs'
import * as Tool2 from './tool.cjs'
console.log(add(1, 2))
console.log(Tool1.add(1, 2))
console.log(Tool2.add(1, 2))
ESM 引用 CommonJS 模块时,等价于 export CommonJS 中 exports,同时 export default CommonJS 中 exports。所以 tool.cjs
可以等价于
// tool.mjs
function add(a, b) {
return a + b
}
export { add }
export default { add }
一些模块已不再支持 CommonJS
如 chalk 在 5.x
版本中完全使用 ESM 语法,不再支持 CommonJS。
其中背景可参见 Pure ESM package 。
如果你的代码还在使用 CommonJS,对于此类模块,只好使用旧版本。
做一个同时支持 CommonJS 和 ESM 的模块
技术上可以让一个模块同时兼容 CommonJS 和 ESM。官方参考文档:https://nodejs.org/api/packages.html#package-entry-points 方法是在模块中同时有 CommonJS 和 ESM 代码(加入分别在 cjs 和 mjs 子目录),在 package.json 中指明两者的入口文件。
// package.json
{
"main": "./cjs/index.js",
"module": "./mjs/index.js",
"exports": {
"require": "./cjs/index.js",
"import": "./mjs/index.js"
}
}
其中的 “exports” 是简写,等价于
// package.json
{
"exports": {
".": {
"require": "./cjs/index.js",
"import": "./mjs/index.js"
}
}
}