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