使用 require() 加载 ECMAScript 模块
【Loading ECMAScript modules using require()】
.mjs 扩展名保留给 ECMAScript 模块。请参阅 确定模块系统 部分了解更多关于哪些文件被解析为 ECMAScript 模块的信息。
【The .mjs extension is reserved for ECMAScript Modules.
See Determining module system section for more info
regarding which files are parsed as ECMAScript modules.】
require() 仅支持加载满足以下要求的 ECMAScript 模块:
- 该模块是完全同步的(不包含顶层
await);并且 - 满足以下其中一个条件:
- 该文件有一个
.mjs扩展名。 - 该文件的扩展名为 '.js',最近的 'package.json' 包含 '类型': “module”'
- 该文件的扩展名为“.js”,最近的“package.json”不包含“type”: “commonjs”“,模块包含ES模块语法。
- 该文件有一个
如果正在加载的 ES 模块符合要求,require() 可以加载它并返回 模块命名空间对象。在这种情况下,它类似于动态 import(),但会同步运行并直接返回命名空间对象。
【If the ES Module being loaded meets the requirements, require() can load it and
return the module namespace object. In this case it is similar to dynamic
import() but is run synchronously and returns the name space object
directly.】
使用以下 ES 模块:
【With the following ES Modules:】
// distance.mjs
export function distance(a, b) { return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2); } // point.mjs
export default class Point {
constructor(x, y) { this.x = x; this.y = y; }
} CommonJS 模块可以使用 require() 来加载它们:
【A CommonJS module can load them with require():】
const distance = require('./distance.mjs');
console.log(distance);
// [Module: null prototype] {
// distance: [Function: distance]
// }
const point = require('./point.mjs');
console.log(point);
// [Module: null prototype] {
// default: [class Point],
// __esModule: true,
// } 为了与将 ES 模块转换为 CommonJS 的现有工具实现互操作性,并且这些工具随后可以通过 require() 加载真实的 ES 模块,如果返回的命名空间包含 default 导出,那么它将包含一个 __esModule: true 属性,以便由工具生成的使用代码能够识别真实 ES 模块中的默认导出。如果命名空间已经定义了 __esModule,则不会添加该属性。此属性是实验性的,未来可能会发生变化。它应仅由将 ES 模块转换为 CommonJS 模块的工具使用,遵循现有生态系统的约定。直接在 CommonJS 中编写的代码应避免依赖该属性。
【For interoperability with existing tools that convert ES Modules into CommonJS,
which could then load real ES Modules through require(), the returned namespace
would contain a __esModule: true property if it has a default export so that
consuming code generated by tools can recognize the default exports in real
ES Modules. If the namespace already defines __esModule, this would not be added.
This property is experimental and can change in the future. It should only be used
by tools converting ES modules into CommonJS modules, following existing ecosystem
conventions. Code authored directly in CommonJS should avoid depending on it.】
当一个 ES 模块同时包含命名导出和默认导出时,require() 返回的结果是 模块命名空间对象,它将默认导出放在 .default 属性中,类似于 import() 返回的结果。要自定义 require(esm) 直接返回的内容,ES 模块可以使用字符串名称 "module.exports" 导出所需的值。
【When an ES Module contains both named exports and a default export, the result returned by require()
is the module namespace object, which places the default export in the .default property, similar to
the results returned by import().
To customize what should be returned by require(esm) directly, the ES Module can export the
desired value using the string name "module.exports".】
// point.mjs
export default class Point {
constructor(x, y) { this.x = x; this.y = y; }
}
// `distance` is lost to CommonJS consumers of this module, unless it's
// added to `Point` as a static property.
export function distance(a, b) { return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2); }
export { Point as 'module.exports' } const Point = require('./point.mjs');
console.log(Point); // [class Point]
// Named exports are lost when 'module.exports' is used
const { distance } = require('./point.mjs');
console.log(distance); // undefined 请注意在上面的示例中,当使用 module.exports 导出名称时,命名导出将不会被 CommonJS 消费者使用。为了让 CommonJS 消费者能够继续访问命名导出,模块可以确保默认导出是一个对象,并将命名导出作为属性附加到该对象上。例如,在上面的示例中,可以将 distance 作为静态方法附加到默认导出 Point 类上。
【Notice in the example above, when the module.exports export name is used, named exports
will be lost to CommonJS consumers. To allow CommonJS consumers to continue accessing
named exports, the module can make sure that the default export is an object with the
named exports attached to it as properties. For example with the example above,
distance can be attached to the default export, the Point class, as a static method.】
export function distance(a, b) { return Math.sqrt((b.x - a.x) ** 2 + (b.y - a.y) ** 2); }
export default class Point {
constructor(x, y) { this.x = x; this.y = y; }
static distance = distance;
}
export { Point as 'module.exports' } const Point = require('./point.mjs');
console.log(Point); // [class Point]
const { distance } = require('./point.mjs');
console.log(distance); // [Function: distance] 如果被 require() 的模块包含顶层 await,或者它所 import 的模块图包含顶层 await,将会抛出 ERR_REQUIRE_ASYNC_MODULE。在这种情况下,用户应使用 import() 加载异步模块。
【If the module being require()'d contains top-level await, or the module
graph it imports contains top-level await,
ERR_REQUIRE_ASYNC_MODULE will be thrown. In this case, users should
load the asynchronous module using import().】
如果启用了 --experimental-print-required-tla,Node.js 不会在评估前抛出 ERR_REQUIRE_ASYNC_MODULE,而是会评估模块,尝试定位顶层 await,并打印它们的位置以帮助用户修复它们。
【If --experimental-print-required-tla is enabled, instead of throwing
ERR_REQUIRE_ASYNC_MODULE before evaluation, Node.js will evaluate the
module, try to locate the top-level awaits, and print their location to
help users fix them.】
使用 require() 加载 ES 模块的支持目前是实验性的,可以使用 --no-experimental-require-module 禁用。要打印该功能的使用位置,请使用 --trace-require-module。
【Support for loading ES modules using require() is currently
experimental and can be disabled using --no-experimental-require-module.
To print where this feature is used, use --trace-require-module.】
可以通过检查 process.features.require_module 是否为 true 来检测此功能。
【This feature can be detected by checking if
process.features.require_module is true.】