跳转至

与 CommonJS 的互操作性

import 语句

import语句可以引用 ES 模块或 CommonJS 模块。 仅在 ES 模块中允许import 语句, 但是 CommonJS 中支持动态import()表达式来加载 ES 模块。

当导入CommonJS 模块时,module.exports对象被作为默认导出提供。 可以使用静态分析提供的命名导出,以方便更好的生态系统兼容性。

require

CommonJS 模块require总是将它引用的文件视为 CommonJS。

不支持使用require加载 ES 模块,因为 ES 模块具有异步执行。 相反,使用import()从 CommonJS 模块加载 ES 模块。

CommonJS 名称空间

CommonJS 模块由一个模块组成。导出对象,该对象可以是任何类型。

当导入 CommonJS 模块时,可以使用 ES 模块默认导入或对应的 sugar 语法可靠地导入:

import { default as cjs } from "cjs";

// The following import statement is "syntax sugar" (equivalent but sweeter)
// for `{ default as cjsSugar }` in the above import statement:
import cjsSugar from "cjs";

console.log(cjs);
console.log(cjs === cjsSugar);
// Prints:
//   <module.exports>
//   true

CommonJS 模块的 ECMAScript 模块命名空间表示形式始终是一个带有default导出键的命名空间,该导出键指向 CommonJS 的module.exports值。

当使用import * as m from 'cjs'或动态导入时,可以直接观察到这个模块命名空间外来对象:

1
2
3
4
5
6
import * as m from "cjs";
console.log(m);
console.log(m === (await import("cjs")));
// Prints:
//   [Module] { default: <module.exports> }
//   true

为了更好地兼容 JS 生态系统中的现有使用,Node.js 还试图确定每个导入的 CommonJS 模块的 CommonJS 命名导出,并使用静态分析过程将它们作为单独的 ES 模块导出提供。

例如,考虑这样一个 CommonJS 模块:

// cjs.cjs
exports.name = "exported";

例如,考虑一个 CommonJS 模块:前面的模块支持 ES 模块中的命名导入:

import { name } from "./cjs.cjs";
console.log(name);
// Prints: 'exported'

import cjs from "./cjs.cjs";
console.log(cjs);
// Prints: { name: 'exported' }

import * as m from "./cjs.cjs";
console.log(m);
// Prints: [Module] { default: { name: 'exported' }, name: 'exported' }

从上一个记录模块名称空间外来对象的示例中可以看出,导入模块时,name导出是从module.exports对象中复制出来的,并直接在 ES 模块名称空间上设置。

对于这些已命名的导出,不会检测到添加到module.exports中的实时绑定更新或新导出。

命名导出的检测基于通用语法模式,但并不总是正确地检测命名导出。 在这些情况下,使用上面描述的默认导入表单可能是更好的选择。

Named exports detection covers many common export patterns, reexport patterns and build tool and transpiler outputs. See cjs-module-lexer for the exact semantics implemented.

命名导出检测包括许多常见的导出模式、再导出模式以及构建工具和转译器输出。 具体实现的语义请参见cjs-module-lexer

ES 模块和 CommonJS 的区别

No require, exports, or module.exports

在大多数情况下,ES 模块import可以用来加载 CommonJS 模块。

如果需要,可以使用module.createRequire()在 ES 模块中构造require函数

No __filename or __dirname

这些 CommonJS 变量在 ES 模块中不可用。

__filename__dirname 用例可以通过import.meta.url复制

无加载插件

ES 模块导入目前不支持Addons

它们可以用module.createRequire()process.dlopen来加载。

No require.resolve

相对解析可以通过new URL('./local', import.meta.url)来处理。

对于一个完整的require.resolve替换,有一个标记的实验import.meta.resolve API。

也可以使用module.createRequire()

No NODE_PATH

NODE_PATH不是解析import说明符的一部分。 如果需要这种行为,请使用符号链接。

No require.extensions

require.extensions不会被import使用。 我们期望将来加载器钩子可以提供这个工作流。

No require.cache

require.cache不会被import使用,因为 ES 模块加载器有自己单独的缓存。