- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议 2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS 模块
- module/esm ECMAScript 模块
- module/package 包模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- stream 流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
Node.js v16.20.0 文档
- Node.js v16.20.0
- 目录
-
导航
- assert 断言
- async_hooks 异步钩子
- async_hooks/context 异步上下文
- buffer 缓冲区
- C++插件
- C/C++插件(使用 Node-API)
- C++嵌入器
- child_process 子进程
- cluster 集群
- CLI 命令行
- console 控制台
- Corepack 核心包
- crypto 加密
- crypto/webcrypto 网络加密
- debugger 调试器
- deprecation 弃用
- dgram 数据报
- diagnostics_channel 诊断通道
- dns 域名服务器
- domain 域
- Error 错误
- events 事件触发器
- fs 文件系统
- global 全局变量
- http 超文本传输协议
- http2 超文本传输协议 2.0
- https 安全超文本传输协议
- inspector 检查器
- Intl 国际化
- module 模块
- module/cjs CommonJS 模块
- module/esm ECMAScript 模块
- module/package 包模块
- net 网络
- os 操作系统
- path 路径
- perf_hooks 性能钩子
- permission 权限
- process 进程
- punycode 域名代码
- querystring 查询字符串
- readline 逐行读取
- repl 交互式解释器
- report 诊断报告
- stream 流
- stream/web 网络流
- string_decoder 字符串解码器
- test 测试
- timers 定时器
- tls 安全传输层
- trace_events 跟踪事件
- tty 终端
- url 网址
- util 实用工具
- v8 引擎
- vm 虚拟机
- wasi 网络汇编系统接口
- worker_threads 工作线程
- zlib 压缩
- 其他版本
模块:ECMAScript 模块#
¥Modules: ECMAScript modules
¥Stability: 2 - Stable
介绍#
¥Introduction
ECMAScript 模块是 官方标准格式,用于打包 JavaScript 代码以供重用。模块使用各种 import
和 export
语句定义。
¥ECMAScript modules are the official standard format to package JavaScript
code for reuse. Modules are defined using a variety of import
and
export
statements.
以下是 ES 模块导出函数的示例:
¥The following example of an ES module exports a function:
// addTwo.mjs
function addTwo(num) {
return num + 2;
}
export { addTwo };
以下是 ES 模块从 addTwo.mjs
导入函数的示例:
¥The following example of an ES module imports the function from addTwo.mjs
:
// app.mjs
import { addTwo } from './addTwo.mjs';
// Prints: 6
console.log(addTwo(4));
Node.js 完全支持当前指定的 ECMAScript 模块,并提供它们与其原始模块格式 CommonJS 之间的互操作性。
¥Node.js fully supports ECMAScript modules as they are currently specified and provides interoperability between them and its original module format, CommonJS.
启用#
¥Enabling
Node.js 有两个模块系统:CommonJS 模块和 ECMAScript 模块。
¥Node.js has two module systems: CommonJS modules and ECMAScript modules.
作者可以通过 .mjs
文件扩展名、package.json
"type"
字段、或 --input-type
标志告诉 Node.js 使用 ECMAScript 模块加载器。在这些情况之外,Node.js 将使用 CommonJS 模块加载器。有关详细信息,请参阅 确定模块系统。
¥Authors can tell Node.js to use the ECMAScript modules loader
via the .mjs
file extension, the package.json
"type"
field, or the
--input-type
flag. Outside of those cases, Node.js will use the CommonJS
module loader. See Determining module system for more details.
包#
¥Packages
此部分已移至 模块:包。
¥This section was moved to Modules: Packages.
import
说明符#
¥import
Specifiers
术语#
¥Terminology
import
语句的说明符是 from
关键字之后的字符串,例如 import { sep } from 'node:path'
中的 'node:path'
。说明符也用于 export from
语句,并作为 import()
表达式的参数。
¥The specifier of an import
statement is the string after the from
keyword,
e.g. 'node:path'
in import { sep } from 'node:path'
. Specifiers are also
used in export from
statements, and as the argument to an import()
expression.
有三种类型的说明符:
¥There are three types of specifiers:
-
相对说明符,如
'./startup.js'
或'../config.mjs'
。它们指的是相对于导入文件位置的路径。这些文件扩展名始终是必需的。¥Relative specifiers like
'./startup.js'
or'../config.mjs'
. They refer to a path relative to the location of the importing file. The file extension is always necessary for these. -
纯说明符,如
'some-package'
或'some-package/shuffle'
。它们可以通过包名称来引用包的主要入口点,或者根据示例分别以包名称为前缀的包中的特定功能模块。只有没有"exports"
字段的包才需要包含文件扩展名。¥Bare specifiers like
'some-package'
or'some-package/shuffle'
. They can refer to the main entry point of a package by the package name, or a specific feature module within a package prefixed by the package name as per the examples respectively. Including the file extension is only necessary for packages without an"exports"
field. -
绝对说明符,如
'file:///opt/nodejs/config.js'
。它们直接且明确地引用完整的路径。¥Absolute specifiers like
'file:///opt/nodejs/config.js'
. They refer directly and explicitly to a full path.
裸说明符解析由 Node.js 模块解析算法 处理。所有其他说明符解析始终仅使用标准的相对 URL 解析语义进行解析。
¥Bare specifier resolutions are handled by the Node.js module resolution algorithm. All other specifier resolutions are always only resolved with the standard relative URL resolution semantics.
就像在 CommonJS 中一样,包中的模块文件可以通过在包名称后附加路径来访问,除非包的 package.json
包含 "exports"
字段,在这种情况下,包中的文件只能通过 "exports"
中定义的路径访问。
¥Like in CommonJS, module files within packages can be accessed by appending a
path to the package name unless the package's package.json
contains an
"exports"
field, in which case files within packages can only be accessed
via the paths defined in "exports"
.
有关适用于 Node.js 模块解析中的裸说明符的这些包解析规则的详细信息,请参阅 包文档。
¥For details on these package resolution rules that apply to bare specifiers in the Node.js module resolution, see the packages documentation.
强制文件扩展名#
¥Mandatory file extensions
当使用 import
关键字解析相对或绝对的说明符时,必须提供文件扩展名。还必须完全指定目录索引(例如 './startup/index.js'
)。
¥A file extension must be provided when using the import
keyword to resolve
relative or absolute specifiers. Directory indexes (e.g. './startup/index.js'
)
must also be fully specified.
此行为与 import
在浏览器环境中的行为方式相匹配,假设服务器是典型配置的。
¥This behavior matches how import
behaves in browser environments, assuming a
typically configured server.
URL#
ES 模块被解析并缓存为 URL。这意味着特殊字符必须是 percent-encoded,例如 #
必须是 %23
,?
必须是 %3F
。
¥ES modules are resolved and cached as URLs. This means that special characters
must be percent-encoded, such as #
with %23
and ?
with %3F
.
支持 file:
、node:
和 data:
URL 协议。除非使用 自定义 HTTPS 加载器,否则 Node.js 本身不支持像 'https://example.com/app.js'
这样的说明符。
¥file:
, node:
, and data:
URL schemes are supported. A specifier like
'https://example.com/app.js'
is not supported natively in Node.js unless using
a custom HTTPS loader.
file:
URL#
如果用于解析模块的 import
说明符具有不同的查询或片段,则会多次加载模块。
¥Modules are loaded multiple times if the import
specifier used to resolve
them has a different query or fragment.
import './foo.mjs?query=1'; // loads ./foo.mjs with query of "?query=1"
import './foo.mjs?query=2'; // loads ./foo.mjs with query of "?query=2"
可以通过 /
、//
、或 file:///
引用卷根。考虑到 URL 和路径解析的差异(比如百分比编码细节),建议导入路径时使用 url.pathToFileURL。
¥The volume root may be referenced via /
, //
, or file:///
. Given the
differences between URL and path resolution (such as percent encoding
details), it is recommended to use url.pathToFileURL when importing a path.
data:
导入#
¥data:
imports
data:
URL 支持使用以下 MIME 类型导入:
¥data:
URLs are supported for importing with the following MIME types:
-
text/javascript
用于 ES 模块¥
text/javascript
for ES modules -
application/json
用于 JSON¥
application/json
for JSON -
application/wasm
用于 Wasm¥
application/wasm
for Wasm
import 'data:text/javascript,console.log("hello!");';
import _ from 'data:application/json,"world!"' assert { type: 'json' };
data:
URL 仅解析内置模块的 裸说明符 和 绝对说明符。解析 相对说明符 不起作用,因为 data:
不是 特别计划。例如,尝试从 data:text/javascript,import "./foo";
加载 ./foo
无法解析,因为 data:
URL 没有相对解析的概念。
¥data:
URLs only resolve bare specifiers for builtin modules
and absolute specifiers. Resolving
relative specifiers does not work because data:
is not a
special scheme. For example, attempting to load ./foo
from data:text/javascript,import "./foo";
fails to resolve because there
is no concept of relative resolution for data:
URLs.
node:
导入#
¥node:
imports
支持 node:
URL 作为加载 Node.js 内置模块的替代方法。此 URL 协议允许有效的绝对的 URL 字符串引用内置模块。
¥node:
URLs are supported as an alternative means to load Node.js builtin
modules. This URL scheme allows for builtin modules to be referenced by valid
absolute URL strings.
import fs from 'node:fs/promises';
导入断言#
¥Import assertions
¥Stability: 1 - Experimental
导入断言提案 为模块导入语句添加了内联语法,以便在模块说明符旁边传递更多信息。
¥The Import Assertions proposal adds an inline syntax for module import statements to pass on more information alongside the module specifier.
import fooData from './foo.json' assert { type: 'json' };
const { default: barData } =
await import('./bar.json', { assert: { type: 'json' } });
Node.js 支持以下 type
值,其断言是强制性的:
¥Node.js supports the following type
values, for which the assertion is
mandatory:
断言 type | 需要用于 |
---|---|
'json' | JSON 模块 |
内置模块#
¥Builtin modules
核心模块 提供其公共 API 的命名导出。还提供了默认导出,其是 CommonJS 导出的值。默认导出可用于修改命名导出等。内置模块的命名导出仅通过调用 module.syncBuiltinESMExports()
进行更新。
¥Core modules provide named exports of their public API. A
default export is also provided which is the value of the CommonJS exports.
The default export can be used for, among other things, modifying the named
exports. Named exports of builtin modules are updated only by calling
module.syncBuiltinESMExports()
.
import EventEmitter from 'node:events';
const e = new EventEmitter();
import { readFile } from 'node:fs';
readFile('./foo.txt', (err, source) => {
if (err) {
console.error(err);
} else {
console.log(source);
}
});
import fs, { readFileSync } from 'node:fs';
import { syncBuiltinESMExports } from 'node:module';
import { Buffer } from 'node:buffer';
fs.readFileSync = () => Buffer.from('Hello, ESM');
syncBuiltinESMExports();
fs.readFileSync === readFileSync;
import()
表达式#
¥import()
expressions
CommonJS 和 ES 模块都支持 动态 import()
。在 CommonJS 模块中它可以用来加载 ES 模块。
¥Dynamic import()
is supported in both CommonJS and ES modules. In CommonJS
modules it can be used to load ES modules.
import.meta
#
import.meta
元属性是包含以下属性的 Object
。
¥The import.meta
meta property is an Object
that contains the following
properties.
import.meta.url
#
这与提供当前模块文件 URL 的浏览器中的定义完全相同。
¥This is defined exactly the same as it is in browsers providing the URL of the current module file.
这可以启用有用的模式,例如相对文件加载
¥This enables useful patterns such as relative file loading:
import { readFileSync } from 'node:fs';
const buffer = readFileSync(new URL('./data.proto', import.meta.url));
import.meta.resolve(specifier[, parent])
#
¥Stability: 1 - Experimental
此特性仅在启用 --experimental-import-meta-resolve
命令标志时可用。
¥This feature is only available with the --experimental-import-meta-resolve
command flag enabled.
-
specifier
<string> 相对于parent
解析的模块说明符。¥
specifier
<string> The module specifier to resolve relative toparent
. -
parent
<string> | <URL> 要解析的绝对的父模块 URL。如果未指定,则使用import.meta.url
的值作为默认值。¥
parent
<string> | <URL> The absolute parent module URL to resolve from. If none is specified, the value ofimport.meta.url
is used as the default. -
返回:<Promise>
¥Returns: <Promise>
提供作用域为每个模块的模块相关解析函数,返回 URL 字符串。
¥Provides a module-relative resolution function scoped to each module, returning the URL string.
const dependencyAsset = await import.meta.resolve('component-lib/asset.css');
import.meta.resolve
还接受第二个参数,它是从中解析的父模块:
¥import.meta.resolve
also accepts a second argument which is the parent module
from which to resolve from:
await import.meta.resolve('./dep', import.meta.url);
这个函数是异步的,因为 Node.js 中的 ES 模块解析器是允许异步的。
¥This function is asynchronous because the ES module resolver in Node.js is allowed to be asynchronous.
与 CommonJS 的互操作性#
¥Interoperability with CommonJS
import
语句#
¥import
statements
import
语句可以引用 ES 模块或 CommonJS 模块。import
语句只允许在 ES 模块中使用,但 CommonJS 支持动态 import()
表达式来加载 ES 模块。
¥An import
statement can reference an ES module or a CommonJS module.
import
statements are permitted only in ES modules, but dynamic import()
expressions are supported in CommonJS for loading ES modules.
导入 CommonJS 模块 时,module.exports
对象作为默认导出提供。命名导出可能可用,由静态分析提供,以方便更好的生态系统兼容性。
¥When importing CommonJS modules, the
module.exports
object is provided as the default export. Named exports may be
available, provided by static analysis as a convenience for better ecosystem
compatibility.
require
#
CommonJS 模块 require
总是将它引用的文件视为 CommonJS。
¥The CommonJS module require
always treats the files it references as CommonJS.
不支持使用 require
加载 ES 模块,因为 ES 模块具有异步执行。而是,使用 import()
从 CommonJS 模块加载 ES 模块。
¥Using require
to load an ES module is not supported because ES modules have
asynchronous execution. Instead, use import()
to load an ES module
from a CommonJS module.
CommonJS 命名空间#
¥CommonJS Namespaces
CommonJS 模块由可以是任何类型的 module.exports
对象组成。
¥CommonJS modules consist of a module.exports
object which can be of any type.
当导入 CommonJS 模块时,可以使用 ES 模块默认导入或其对应的语法糖可靠地导入:
¥When importing a CommonJS module, it can be reliably imported using the ES module default import or its corresponding sugar syntax:
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
值的命名空间。
¥The ECMAScript Module Namespace representation of a CommonJS module is always
a namespace with a default
export key pointing to the CommonJS
module.exports
value.
当使用 import * as m from 'cjs'
或动态导入时,可以直接观察到此模块命名空间外来对象:
¥This Module Namespace Exotic Object can be directly observed either when using
import * as m from 'cjs'
or a dynamic import:
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 模块导出提供。
¥For better compatibility with existing usage in the JS ecosystem, Node.js in addition attempts to determine the CommonJS named exports of every imported CommonJS module to provide them as separate ES module exports using a static analysis process.
例如,考虑编写的 CommonJS 模块:
¥For example, consider a CommonJS module written:
// cjs.cjs
exports.name = 'exported';
前面的模块支持 ES 模块中的命名导入:
¥The preceding module supports named imports in ES modules:
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 模块命名空间上。
¥As can be seen from the last example of the Module Namespace Exotic Object being
logged, the name
export is copied off of the module.exports
object and set
directly on the ES module namespace when the module is imported.
未检测到这些命名导出的实时绑定更新或添加到 module.exports
的新导出。
¥Live binding updates or new exports added to module.exports
are not detected
for these named exports.
命名导出的检测基于通用语法模式,但并不总是正确地检测命名导出。在这些情况下,使用上述默认导入形式可能是更好的选择。
¥The detection of named exports is based on common syntax patterns but does not always correctly detect named exports. In these cases, using the default import form described above can be a better option.
命名导出检测涵盖了许多常见的导出模式、再导出模式、以及构建工具和转译器输出。有关实现的确切语义,请参阅 cjs-module-lexer。
¥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.
ES 模块和 CommonJS 的区别#
¥Differences between ES modules and CommonJS
无 require
、exports
或 module.exports
#
¥No require
, exports
, or module.exports
在大多数情况下,可以使用 ES 模块 import
加载 CommonJS 模块。
¥In most cases, the ES module import
can be used to load CommonJS modules.
如果需要,可以使用 module.createRequire()
在 ES 模块中构造 require
函数。
¥If needed, a require
function can be constructed within an ES module using
module.createRequire()
.
无 __filename
或 __dirname
#
¥No __filename
or __dirname
这些 CommonJS 变量在 ES 模块中不可用。
¥These CommonJS variables are not available in ES modules.
__filename
和 __dirname
用例可以通过 import.meta.url
复制。
¥__filename
and __dirname
use cases can be replicated via
import.meta.url
.
没有原生模块加载#
¥No Native Module Loading
ES 模块导入当前不支持原生模块。
¥Native modules are not currently supported with ES module imports.
它们可以改为加载 module.createRequire()
或 process.dlopen
。
¥They can instead be loaded with module.createRequire()
or
process.dlopen
.
没有 require.resolve
#
¥No require.resolve
相对解析可以通过 new URL('./local', import.meta.url)
处理。
¥Relative resolution can be handled via new URL('./local', import.meta.url)
.
对于完整的 require.resolve
替换,有标记的实验性 import.meta.resolve
API。
¥For a complete require.resolve
replacement, there is a flagged experimental
import.meta.resolve
API.
也可以使用 module.createRequire()
。
¥Alternatively module.createRequire()
can be used.
没有 NODE_PATH
#
¥No NODE_PATH
NODE_PATH
不是解析 import
说明符的一部分。如果需要这种行为,则使用符号链接。
¥NODE_PATH
is not part of resolving import
specifiers. Please use symlinks
if this behavior is desired.
没有 require.extensions
#
¥No require.extensions
require.extensions
没有被 import
使用。期望加载器钩子在未来可以提供这个工作流。
¥require.extensions
is not used by import
. The expectation is that loader
hooks can provide this workflow in the future.
没有 require.cache
#
¥No require.cache
require.cache
没有被 import
使用,因为 ES 模块加载器有自己独立的缓存。
¥require.cache
is not used by import
as the ES module loader has its own
separate cache.
JSON 模块#
¥JSON modules
¥Stability: 1 - Experimental
import
可以引用 JSON 文件:
¥JSON files can be referenced by import
:
import packageConfig from './package.json' assert { type: 'json' };
assert { type: 'json' }
语法是强制性的;见 导入断言。
¥The assert { type: 'json' }
syntax is mandatory; see Import Assertions.
导入的 JSON 只暴露一个 default
导出。不支持命名导出。在 CommonJS 缓存中创建缓存条目,以避免重复。如果 JSON 模块已经从同一路径导入,则在 CommonJS 中返回相同的对象。
¥The imported JSON only exposes a default
export. There is no support for named
exports. A cache entry is created in the CommonJS cache to avoid duplication.
The same object is returned in CommonJS if the JSON module has already been
imported from the same path.
Wasm 模块#
¥Wasm modules
¥Stability: 1 - Experimental
在 --experimental-wasm-modules
标志下支持导入 WebAssembly 模块,允许将任何 .wasm
文件作为普通模块导入,同时也支持它们的模块导入。
¥Importing WebAssembly modules is supported under the
--experimental-wasm-modules
flag, allowing any .wasm
files to be
imported as normal modules while also supporting their module imports.
这种整合是符合 WebAssembly 的 ES 模块集成提案 的。
¥This integration is in line with the ES Module Integration Proposal for WebAssembly.
例如,index.mjs
包含:
¥For example, an index.mjs
containing:
import * as M from './module.wasm';
console.log(M);
在以下条件下执行:
¥executed under:
node --experimental-wasm-modules index.mjs
将为 module.wasm
的实例化提供导出接口。
¥would provide the exports interface for the instantiation of module.wasm
.
顶层 await
#
¥Top-level await
await
关键字可以用在 ECMAScript 模块的顶层主体中。
¥The await
keyword may be used in the top level body of an ECMAScript module.
假设 a.mjs
具有
¥Assuming an a.mjs
with
export const five = await Promise.resolve(5);
并且 b.mjs
具有
¥And a b.mjs
with
import { five } from './a.mjs';
console.log(five); // Logs `5`
node b.mjs # works
如果顶层 await
表达式永远无法解析,则 node
进程将退出并返回 13
状态码。
¥If a top level await
expression never resolves, the node
process will exit
with a 13
status code.
import { spawn } from 'node:child_process';
import { execPath } from 'node:process';
spawn(execPath, [
'--input-type=module',
'--eval',
// Never-resolving Promise:
'await new Promise(() => {})',
]).once('exit', (code) => {
console.log(code); // Logs `13`
});
HTTPS 和 HTTP 导入#
¥HTTPS and HTTP imports
¥Stability: 1 - Experimental
在 --experimental-network-imports
标志下支持使用 https:
和 http:
导入基于网络的模块。这允许类似网络浏览器的导入在 Node.js 中工作,但由于应用稳定性和安全问题在特权环境而不是浏览器沙箱中运行时会有所不同,因此存在一些差异。
¥Importing network based modules using https:
and http:
is supported under
the --experimental-network-imports
flag. This allows web browser-like imports
to work in Node.js with a few differences due to application stability and
security concerns that are different when running in a privileged environment
instead of a browser sandbox.
导入仅限于 HTTP/1#
¥Imports are limited to HTTP/1
尚不支持 HTTP/2 和 HTTP/3 的自动协议协商。
¥Automatic protocol negotiation for HTTP/2 and HTTP/3 is not yet supported.
HTTP 仅限于环回地址#
¥HTTP is limited to loopback addresses
http:
易受中间人攻击,不允许用于 IPv4 地址 127.0.0.0/8
(127.0.0.1
到 127.255.255.255
)和 IPv6 地址 ::1
之外的地址。对 http:
的支持旨在用于本地开发。
¥http:
is vulnerable to man-in-the-middle attacks and is not allowed to be
used for addresses outside of the IPv4 address 127.0.0.0/8
(127.0.0.1
to
127.255.255.255
) and the IPv6 address ::1
. Support for http:
is intended
to be used for local development.
身份验证永远不会发送到目标服务器。#
¥Authentication is never sent to the destination server.
Authorization
、Cookie
和 Proxy-Authorization
标头未发送到服务器。避免在部分导入的 URL 中包含用户信息。正在研究在服务器上安全使用这些的安全模型。
¥Authorization
, Cookie
, and Proxy-Authorization
headers are not sent to the
server. Avoid including user info in parts of imported URLs. A security model
for safely using these on the server is being worked on.
永远不会在目标服务器上检查 CORS#
¥CORS is never checked on the destination server
CORS 旨在允许服务器将 API 的使用者限制为一组特定的主机。这不受支持,因为它对于基于服务器的实现没有意义。
¥CORS is designed to allow a server to limit the consumers of an API to a specific set of hosts. This is not supported as it does not make sense for a server-based implementation.
无法加载非网络依赖#
¥Cannot load non-network dependencies
这些模块不能访问不超过 http:
或 https:
的其他模块。要在避免安全问题的同时仍然访问本地模块,则传入对本地依赖的引用:
¥These modules cannot access other modules that are not over http:
or https:
.
To still access local modules while avoiding the security concern, pass in
references to the local dependencies:
// file.mjs
import worker_threads from 'node:worker_threads';
import { configure, resize } from 'https://example.com/imagelib.mjs';
configure({ worker_threads });
// https://example.com/imagelib.mjs
let worker_threads;
export function configure(opts) {
worker_threads = opts.worker_threads;
}
export function resize(img, size) {
// Perform resizing in worker_thread to avoid main thread blocking
}
默认情况下不启用基于网络的加载#
¥Network-based loading is not enabled by default
目前,需要 --experimental-network-imports
标志来启用通过 http:
或 https:
加载资源。将来,将使用不同的机制来执行此操作。需要选择加入以防止不经意间使用可能影响 Node.js 应用可靠性的潜在可变状态的传递依赖。
¥For now, the --experimental-network-imports
flag is required to enable loading
resources over http:
or https:
. In the future, a different mechanism will be
used to enforce this. Opt-in is required to prevent transitive dependencies
inadvertently using potentially mutable state that could affect reliability
of Node.js applications.
加载器#
¥Loaders
¥Stability: 1 - Experimental
此 API 目前正在重新设计,并且仍会发生变化。
¥This API is currently being redesigned and will still change.
要自定义默认的模块解析,则可以选择通过 Node.js 的 --experimental-loader ./loader-name.mjs
参数提供加载器钩子。
¥To customize the default module resolution, loader hooks can optionally be
provided via a --experimental-loader ./loader-name.mjs
argument to Node.js.
使用钩子时,它们适用于入口点和所有 import
调用。它们不适用于 require
调用;那些仍然遵循 CommonJS 规则。
¥When hooks are used they apply to the entry point and all import
calls. They
won't apply to require
calls; those still follow CommonJS rules.
加载器遵循 --require
的模式:
¥Loaders follow the pattern of --require
:
node \
--experimental-loader unpkg \
--experimental-loader http-to-https \
--experimental-loader cache-buster
它们按以下顺序调用:cache-buster
调用 http-to-https
,http-to-https
调用 unpkg
。
¥These are called in the following sequence: cache-buster
calls
http-to-https
which calls unpkg
.
钩子#
¥Hooks
钩子是链的一部分,即使该链仅由一个自定义(用户提供的)钩子和始终存在的默认钩子组成。钩子函数嵌套:每个都必须始终返回一个普通对象,并且链接是由于每个函数调用 next<hookName>()
而发生的,next<hookName>()
是对后续加载程序钩子的引用。
¥Hooks are part of a chain, even if that chain consists of only one custom
(user-provided) hook and the default hook, which is always present. Hook
functions nest: each one must always return a plain object, and chaining happens
as a result of each function calling next<hookName>()
, which is a reference
to the subsequent loader’s hook.
返回缺少必需属性的值的钩子会触发异常。没有调用 next<hookName>()
和没有返回 shortCircuit: true
就返回的钩子也会触发异常。这些错误有助于防止链中的意外中断。
¥A hook that returns a value lacking a required property triggers an exception.
A hook that returns without calling next<hookName>()
and without returning
shortCircuit: true
also triggers an exception. These errors are to help
prevent unintentional breaks in the chain.
resolve(specifier, context, nextResolve)
#
加载程序 API 正在重新设计。这个钩子可能会消失或者它的签名可能会改变。不要依赖下面描述的 API。
¥The loaders API is being redesigned. This hook may disappear or its signature may change. Do not rely on the API described below.
-
specifier
<string> -
context
<Object>-
conditions
<string[]> 相关package.json
的导出条件¥
conditions
<string[]> Export conditions of the relevantpackage.json
-
importAssertions
<Object> -
parentURL
<string> | <undefined> 导入此模块的模块,如果这是 Node.js 入口点,则为未定义¥
parentURL
<string> | <undefined> The module importing this one, or undefined if this is the Node.js entry point
-
-
nextResolve
<Function> 链中后续的resolve
钩子,或者用户提供的最后一个resolve
钩子之后的 Node.js 默认resolve
钩子¥
nextResolve
<Function> The subsequentresolve
hook in the chain, or the Node.js defaultresolve
hook after the last user-suppliedresolve
hook -
返回:<Object>
¥Returns: <Object>
-
format
<string> | <null> | <undefined> 加载钩子的提示(可能会被忽略)'builtin' | 'commonjs' | 'json' | 'module' | 'wasm'
¥
format
<string> | <null> | <undefined> A hint to the load hook (it might be ignored)'builtin' | 'commonjs' | 'json' | 'module' | 'wasm'
-
shortCircuit
<undefined> | <boolean> 此钩子打算终止resolve
钩子链的信号。默认值:false
¥
shortCircuit
<undefined> | <boolean> A signal that this hook intends to terminate the chain ofresolve
hooks. Default:false
-
url
<string> 此输入解析到的绝对 URL¥
url
<string> The absolute URL to which this input resolves
-
resolve
钩子链负责解析给定模块说明符和父 URL 的文件 URL,以及可选的格式(例如 'module'
)作为 load
钩子的提示。如果指定了格式,load
钩子最终负责提供最终的 format
值(并且可以随意忽略 resolve
提供的提示);如果 resolve
提供 format
,则需要自定义 load
钩子,即使只是将值传递给 Node.js 默认的 load
钩子。
¥The resolve
hook chain is responsible for resolving file URL for a given
module specifier and parent URL, and optionally its format (such as 'module'
)
as a hint to the load
hook. If a format is specified, the load
hook is
ultimately responsible for providing the final format
value (and it is free to
ignore the hint provided by resolve
); if resolve
provides a format
, a
custom load
hook is required even if only to pass the value to the Node.js
default load
hook.
模块说明符是 import
语句或 import()
表达式中的字符串。
¥The module specifier is the string in an import
statement or
import()
expression.
父 URL 是导入此模块的 URL,如果这是应用的主要入口点,则为 undefined
。
¥The parent URL is the URL of the module that imported this one, or undefined
if this is the main entry point for the application.
context
中的 conditions
属性是适用于此解析请求的 包导出条件 的条件数组。它们可用于在别处查找条件映射或在调用默认解析逻辑时修改列表。
¥The conditions
property in context
is an array of conditions for
package exports conditions that apply to this resolution
request. They can be used for looking up conditional mappings elsewhere or to
modify the list when calling the default resolution logic.
当前的 包导出条件 总是在传入钩子的 context.conditions
数组中。为了保证在调用 defaultResolve
时默认的 Node.js 模块说明符解析行为,传递给它的 context.conditions
数组必须包括最初传递到 resolve
钩子的 context.conditions
数组的所有元素。
¥The current package exports conditions are always in
the context.conditions
array passed into the hook. To guarantee default
Node.js module specifier resolution behavior when calling defaultResolve
, the
context.conditions
array passed to it must include all elements of the
context.conditions
array originally passed into the resolve
hook.
export async function resolve(specifier, context, nextResolve) {
const { parentURL = null } = context;
if (Math.random() > 0.5) { // Some condition.
// For some or all specifiers, do some custom logic for resolving.
// Always return an object of the form {url: <string>}.
return {
shortCircuit: true,
url: parentURL ?
new URL(specifier, parentURL).href :
new URL(specifier).href,
};
}
if (Math.random() < 0.5) { // Another condition.
// When calling `defaultResolve`, the arguments can be modified. In this
// case it's adding another value for matching conditional exports.
return nextResolve(specifier, {
...context,
conditions: [...context.conditions, 'another-condition'],
});
}
// Defer to the next hook in the chain, which would be the
// Node.js default resolve if this is the last user-specified loader.
return nextResolve(specifier);
}
load(url, context, nextLoad)
#
加载程序 API 正在重新设计。这个钩子可能会消失或者它的签名可能会改变。不要依赖下面描述的 API。
¥The loaders API is being redesigned. This hook may disappear or its signature may change. Do not rely on the API described below.
在此 API 的先前版本中,它分为 3 个独立的、现已弃用的钩子(
getFormat
、getSource
和transformSource
)。¥In a previous version of this API, this was split across 3 separate, now deprecated, hooks (
getFormat
,getSource
, andtransformSource
).
-
url
<string>resolve
链返回的 URL¥
url
<string> The URL returned by theresolve
chain -
context
<Object>-
conditions
<string[]> 相关package.json
的导出条件¥
conditions
<string[]> Export conditions of the relevantpackage.json
-
format
<string> | <null> | <undefined>resolve
钩子链可选提供的格式¥
format
<string> | <null> | <undefined> The format optionally supplied by theresolve
hook chain -
importAssertions
<Object>
-
-
nextLoad
<Function> 链中后续的load
钩子,或者用户提供的最后一个load
钩子之后的 Node.js 默认load
钩子¥
nextLoad
<Function> The subsequentload
hook in the chain, or the Node.js defaultload
hook after the last user-suppliedload
hook -
返回:<Object>
¥Returns: <Object>
-
format
<string> -
shortCircuit
<undefined> | <boolean> 此钩子打算终止resolve
钩子链的信号。默认值:false
¥
shortCircuit
<undefined> | <boolean> A signal that this hook intends to terminate the chain ofresolve
hooks. Default:false
-
source
<string> | <ArrayBuffer> | <TypedArray> Node.js 评估的来源¥
source
<string> | <ArrayBuffer> | <TypedArray> The source for Node.js to evaluate
-
load
钩子提供了一种方式来定义确定网址应如何解释、检索、以及解析的自定义方法。它还负责验证导入断言。
¥The load
hook provides a way to define a custom method of determining how
a URL should be interpreted, retrieved, and parsed. It is also in charge of
validating the import assertion.
format
的最终值必须是以下之一:
¥The final value of format
must be one of the following:
format | 描述 | load 返回的 source 可接受的类型 |
---|---|---|
'builtin' | 加载 Node.js 内置模块 | 不适用 |
'commonjs' | 加载 Node.js CommonJS 模块 | 不适用 |
'json' | 加载 JSON 文件 | { string , ArrayBuffer , TypedArray } |
'module' | 加载 ES 模块 | { string , ArrayBuffer , TypedArray } |
'wasm' | 加载 WebAssembly 模块 | { ArrayBuffer , TypedArray } |
source
的值对于类型 'builtin'
被忽略,因为目前无法替换 Node.js 内置(核心)模块的值。对于类型 'commonjs'
,source
的值被忽略,因为 CommonJS 模块加载器没有为 ES 模块加载器提供覆盖 CommonJS 模块返回值 的机制。这个限制将来可能会被克服。
¥The value of source
is ignored for type 'builtin'
because currently it is
not possible to replace the value of a Node.js builtin (core) module. The value
of source
is ignored for type 'commonjs'
because the CommonJS module loader
does not provide a mechanism for the ES module loader to override the
CommonJS module return value. This limitation might be
overcome in the future.
警告:ESM
load
钩子和来自 CommonJS 模块的命名空间导出不兼容。尝试将它们一起使用将导致导入的对象为空。这可能会在未来得到解决。¥Caveat: The ESM
load
hook and namespaced exports from CommonJS modules are incompatible. Attempting to use them together will result in an empty object from the import. This may be addressed in the future.
这些类型都对应于 ECMAScript 中定义的类。
¥These types all correspond to classes defined in ECMAScript.
-
特定的
ArrayBuffer
对象是SharedArrayBuffer
。¥The specific
ArrayBuffer
object is aSharedArrayBuffer
. -
特定的
TypedArray
对象是Uint8Array
。¥The specific
TypedArray
object is aUint8Array
.
如果基于文本的格式(即 'json'
、'module'
)的源值不是字符串,则使用 util.TextDecoder
将其转换为字符串。
¥If the source value of a text-based format (i.e., 'json'
, 'module'
)
is not a string, it is converted to a string using util.TextDecoder
.
load
钩子提供了一种方法来定义用于检索 ES 模块说明符的源代码的自定义方法。这将允许加载器潜在地避免从磁盘读取文件。它还可以用于将无法识别的格式映射到支持的格式,例如 yaml
到 module
。
¥The load
hook provides a way to define a custom method for retrieving the
source code of an ES module specifier. This would allow a loader to potentially
avoid reading files from disk. It could also be used to map an unrecognized
format to a supported one, for example yaml
to module
.
export async function load(url, context, nextLoad) {
const { format } = context;
if (Math.random() > 0.5) { // Some condition
/*
For some or all URLs, do some custom logic for retrieving the source.
Always return an object of the form {
format: <string>,
source: <string|buffer>,
}.
*/
return {
format,
shortCircuit: true,
source: '...',
};
}
// Defer to the next hook in the chain.
return nextLoad(url);
}
在更高级的场景中,这也可用于将不受支持的来源转换为受支持的来源(请参阅下面的 示例)。
¥In a more advanced scenario, this can also be used to transform an unsupported source to a supported one (see Examples below).
globalPreload()
#
加载程序 API 正在重新设计。这个钩子可能会消失或者它的签名可能会改变。不要依赖下面描述的 API。
¥The loaders API is being redesigned. This hook may disappear or its signature may change. Do not rely on the API described below.
在此 API 的先前版本中,此钩子名为
getGlobalPreloadCode
。¥In a previous version of this API, this hook was named
getGlobalPreloadCode
.
-
context
<Object> 辅助预加载代码的信息¥
context
<Object> Information to assist the preload codeport
<MessagePort>
-
返回:<string> 应用启动前运行的代码
¥Returns: <string> Code to run before application startup
有时可能需要在应用运行所在的同一全局作用域内运行一些代码。此钩子允许返回在启动时作为宽松模式脚本运行的字符串。
¥Sometimes it might be necessary to run some code inside of the same global scope that the application runs in. This hook allows the return of a string that is run as a sloppy-mode script on startup.
类似于 CommonJS 封装器的工作方式,代码在隐式函数范围内运行。唯一的参数是一个类似 require
的函数,可用于加载像 "fs" 这样的内置函数:getBuiltin(request: string)
。
¥Similar to how CommonJS wrappers work, the code runs in an implicit function
scope. The only argument is a require
-like function that can be used to load
builtins like "fs": getBuiltin(request: string)
.
如果代码需要更高级的 require
功能,则必须使用 module.createRequire()
构造自己的 require
。
¥If the code needs more advanced require
features, it has to construct
its own require
using module.createRequire()
.
export function globalPreload(context) {
return `\
globalThis.someInjectedProperty = 42;
console.log('I just set some globals!');
const { createRequire } = getBuiltin('module');
const { cwd } = getBuiltin('process');
const require = createRequire(cwd() + '/<preload>');
// [...]
`;
}
为了允许应用和加载器之间的通信,向预加载代码提供了另一个参数:port
。这可以作为加载器钩子的参数和钩子返回的源文本内部。必须注意正确调用 port.ref()
和 port.unref()
以防止进程处于无法正常关闭的状态。
¥In order to allow communication between the application and the loader, another
argument is provided to the preload code: port
. This is available as a
parameter to the loader hook and inside of the source text returned by the hook.
Some care must be taken in order to properly call port.ref()
and
port.unref()
to prevent a process from being in a state where it won't
close normally.
/**
* This example has the application context send a message to the loader
* and sends the message back to the application context
*/
export function globalPreload({ port }) {
port.onmessage = (evt) => {
port.postMessage(evt.data);
};
return `\
port.postMessage('console.log("I went to the Loader and back");');
port.onmessage = (evt) => {
eval(evt.data);
};
`;
}
示例#
¥Examples
各种加载器钩子可以一起使用来完成对 Node.js 代码加载和评估行为的广泛定制。
¥The various loader hooks can be used together to accomplish wide-ranging customizations of the Node.js code loading and evaluation behaviors.
HTTPS 加载器#
¥HTTPS loader
在当前的 Node.js 中,以 https://
开头的说明符是实验性的(请参阅 HTTPS 和 HTTP 导入)。
¥In current Node.js, specifiers starting with https://
are experimental (see
HTTPS and HTTP imports).
下面的加载器注册钩子以启用对此类说明符的基本支持。虽然这看起来像是对 Node.js 核心功能的重大改进,但实际使用此加载器有很大的缺点:性能比从磁盘加载文件慢得多,没有缓存,也没有安全性。
¥The loader below registers hooks to enable rudimentary support for such specifiers. While this may seem like a significant improvement to Node.js core functionality, there are substantial downsides to actually using this loader: performance is much slower than loading files from disk, there is no caching, and there is no security.
// https-loader.mjs
import { get } from 'node:https';
export function resolve(specifier, context, nextResolve) {
const { parentURL = null } = context;
// Normally Node.js would error on specifiers starting with 'https://', so
// this hook intercepts them and converts them into absolute URLs to be
// passed along to the later hooks below.
if (specifier.startsWith('https://')) {
return {
shortCircuit: true,
url: specifier
};
} else if (parentURL && parentURL.startsWith('https://')) {
return {
shortCircuit: true,
url: new URL(specifier, parentURL).href,
};
}
// Let Node.js handle all other specifiers.
return nextResolve(specifier);
}
export function load(url, context, nextLoad) {
// For JavaScript to be loaded over the network, we need to fetch and
// return it.
if (url.startsWith('https://')) {
return new Promise((resolve, reject) => {
get(url, (res) => {
let data = '';
res.on('data', (chunk) => data += chunk);
res.on('end', () => resolve({
// This example assumes all network-provided JavaScript is ES module
// code.
format: 'module',
shortCircuit: true,
source: data,
}));
}).on('error', (err) => reject(err));
});
}
// Let Node.js handle all other URLs.
return nextLoad(url);
}
// main.mjs
import { VERSION } from 'https://coffeescript.org/browser-compiler-modern/coffeescript.js';
console.log(VERSION);
使用前面的加载器,运行 node --experimental-loader ./https-loader.mjs ./main.mjs
会在 main.mjs
中的 URL 处按照模块打印当前版本的 CoffeeScript。
¥With the preceding loader, running
node --experimental-loader ./https-loader.mjs ./main.mjs
prints the current version of CoffeeScript per the module at the URL in
main.mjs
.
转译加载器#
¥Transpiler loader
可以使用 load
钩子 将 Node.js 无法理解的格式的源代码转换为 JavaScript。然而,在调用该钩子之前,resolve
钩子 需要告诉 Node.js 不要对未知文件类型抛出错误。
¥Sources that are in formats Node.js doesn't understand can be converted into
JavaScript using the load
hook. Before that hook gets called,
however, a resolve
hook needs to tell Node.js not to
throw an error on unknown file types.
这比在运行 Node.js 之前转换源文件的性能要差;转译器加载器应该只用于开发和测试目的。
¥This is less performant than transpiling source files before running Node.js; a transpiler loader should only be used for development and testing purposes.
// coffeescript-loader.mjs
import { readFile } from 'node:fs/promises';
import { dirname, extname, resolve as resolvePath } from 'node:path';
import { cwd } from 'node:process';
import { fileURLToPath, pathToFileURL } from 'node:url';
import CoffeeScript from 'coffeescript';
const baseURL = pathToFileURL(`${cwd()}/`).href;
// CoffeeScript files end in .coffee, .litcoffee, or .coffee.md.
const extensionsRegex = /\.coffee$|\.litcoffee$|\.coffee\.md$/;
export async function resolve(specifier, context, nextResolve) {
if (extensionsRegex.test(specifier)) {
const { parentURL = baseURL } = context;
// Node.js normally errors on unknown file extensions, so return a URL for
// specifiers ending in the CoffeeScript file extensions.
return {
shortCircuit: true,
url: new URL(specifier, parentURL).href
};
}
// Let Node.js handle all other specifiers.
return nextResolve(specifier);
}
export async function load(url, context, nextLoad) {
if (extensionsRegex.test(url)) {
// Now that we patched resolve to let CoffeeScript URLs through, we need to
// tell Node.js what format such URLs should be interpreted as. Because
// CoffeeScript transpiles into JavaScript, it should be one of the two
// JavaScript formats: 'commonjs' or 'module'.
// CoffeeScript files can be either CommonJS or ES modules, so we want any
// CoffeeScript file to be treated by Node.js the same as a .js file at the
// same location. To determine how Node.js would interpret an arbitrary .js
// file, search up the file system for the nearest parent package.json file
// and read its "type" field.
const format = await getPackageType(url);
// When a hook returns a format of 'commonjs', `source` is be ignored.
// To handle CommonJS files, a handler needs to be registered with
// `require.extensions` in order to process the files with the CommonJS
// loader. Avoiding the need for a separate CommonJS handler is a future
// enhancement planned for ES module loaders.
if (format === 'commonjs') {
return {
format,
shortCircuit: true,
};
}
const { source: rawSource } = await nextLoad(url, { ...context, format });
// This hook converts CoffeeScript source code into JavaScript source code
// for all imported CoffeeScript files.
const transformedSource = coffeeCompile(rawSource.toString(), url);
return {
format,
shortCircuit: true,
source: transformedSource,
};
}
// Let Node.js handle all other URLs.
return nextLoad(url);
}
async function getPackageType(url) {
// `url` is only a file path during the first iteration when passed the
// resolved url from the load() hook
// an actual file path from load() will contain a file extension as it's
// required by the spec
// this simple truthy check for whether `url` contains a file extension will
// work for most projects but does not cover some edge-cases (such as
// extensionless files or a url ending in a trailing space)
const isFilePath = !!extname(url);
// If it is a file path, get the directory it's in
const dir = isFilePath ?
dirname(fileURLToPath(url)) :
url;
// Compose a file path to a package.json in the same directory,
// which may or may not exist
const packagePath = resolvePath(dir, 'package.json');
// Try to read the possibly nonexistent package.json
const type = await readFile(packagePath, { encoding: 'utf8' })
.then((filestring) => JSON.parse(filestring).type)
.catch((err) => {
if (err?.code !== 'ENOENT') console.error(err);
});
// Ff package.json existed and contained a `type` field with a value, voila
if (type) return type;
// Otherwise, (if not at the root) continue checking the next directory up
// If at the root, stop and return false
return dir.length > 1 && getPackageType(resolvePath(dir, '..'));
}
# main.coffee
import { scream } from './scream.coffee'
console.log scream 'hello, world'
import { version } from 'node:process'
console.log "Brought to you by Node.js version #{version}"
# scream.coffee
export scream = (str) -> str.toUpperCase()
使用前面的加载器,运行 node --experimental-loader ./coffeescript-loader.mjs main.coffee
会导致 main.coffee
在其源代码从磁盘加载之后但在 Node.js 执行之前被转换为 JavaScript;对于通过任何加载文件的 import
语句引用的任何 .coffee
、.litcoffee
或 .coffee.md
文件,依此类推。
¥With the preceding loader, running
node --experimental-loader ./coffeescript-loader.mjs main.coffee
causes main.coffee
to be turned into JavaScript after its source code is
loaded from disk but before Node.js executes it; and so on for any .coffee
,
.litcoffee
or .coffee.md
files referenced via import
statements of any
loaded file.
解析算法#
¥Resolution algorithm
特性#
¥Features
解析器具有以下属性:
¥The resolver has the following properties:
-
ES 模块使用的基于 FileURL 的解析
¥FileURL-based resolution as is used by ES modules
-
支持内置模块加载
¥Support for builtin module loading
-
相对和绝对的网址解析
¥Relative and absolute URL resolution
-
没有默认的扩展名
¥No default extensions
-
没有主文件夹
¥No folder mains
-
通过 node_modules 进行裸说明符包解析查找
¥Bare specifier package resolution lookup through node_modules
解析器算法#
¥Resolver algorithm
加载 ES 模块说明符的算法通过下面的 ESM_RESOLVE 方法给出。它返回相对于 parentURL 的模块说明符的解析 URL。
¥The algorithm to load an ES module specifier is given through the ESM_RESOLVE method below. It returns the resolved URL for a module specifier relative to a parentURL.
确定已解析 URL 的模块格式的算法由 ESM_FORMAT 提供,它返回任何文件的唯一模块格式。"module" 格式为 ECMAScript 模块返回,而 "commonjs" 格式用于指示通过旧版 CommonJS 加载器加载。可以在未来的更新中扩展其他格式,例如 "addon"。
¥The algorithm to determine the module format of a resolved URL is provided by ESM_FORMAT, which returns the unique module format for any file. The "module" format is returned for an ECMAScript Module, while the "commonjs" format is used to indicate loading through the legacy CommonJS loader. Additional formats such as "addon" can be extended in future updates.
在以下算法中,除非另有说明,否则所有子程序错误都将作为这些顶层程序的错误传播。
¥In the following algorithms, all subroutine errors are propagated as errors of these top-level routines unless stated otherwise.
defaultConditions 是条件环境名称数组,["node", "import"]
。
¥defaultConditions is the conditional environment name array,
["node", "import"]
.
解析器可能会抛出以下错误:
¥The resolver can throw the following errors:
-
无效的模块说明符:模块说明符是无效的 URL、包名称或包的子路径说明符。
¥Invalid Module Specifier: Module specifier is an invalid URL, package name or package subpath specifier.
-
无效的包配置:package.json 配置无效或包含无效配置。
¥Invalid Package Configuration: package.json configuration is invalid or contains an invalid configuration.
-
无效的包目标:包导出或导入为包定义了一个目标模块,该模块是无效类型或字符串目标。
¥Invalid Package Target: Package exports or imports define a target module for the package that is an invalid type or string target.
-
未导出的包路径:包导出不为给定模块定义或允许包中的目标子路径。
¥Package Path Not Exported: Package exports do not define or permit a target subpath in the package for the given module.
-
包导入未定义:包导入不定义说明符。
¥Package Import Not Defined: Package imports do not define the specifier.
-
未找到模块:请求的包或模块不存在。
¥Module Not Found: The package or module requested does not exist.
-
不支持的目录导入:解析的路径对应于一个目录,该目录不是模块导入的受支持目标。
¥Unsupported Directory Import: The resolved path corresponds to a directory, which is not a supported target for module imports.
解析器算法规范#
¥Resolver Algorithm Specification
ESM_RESOLVE(specifier, parentURL)
让 resolved 为未定义。
¥Let resolved be undefined.
如果说明符是有效的 URL,则
¥If specifier is a valid URL, then
将 resolved 设置为将说明符解析和重新序列化为 URL 的结果。
¥Set resolved to the result of parsing and reserializing specifier as a URL.
否则,如果说明符以 "/"、"./" 或 "../" 开头,则
¥Otherwise, if specifier starts with "/", "./", or "../", then
将 resolved 设置为说明符相对于 parentURL 的 URL 解析。
¥Set resolved to the URL resolution of specifier relative to parentURL.
否则,如果说明符以 "" 开头,则
¥Otherwise, if specifier starts with "#", then
将已解析设置为 PACKAGE_IMPORTS_RESOLVE(specifier,parentURL,defaultConditions) 结果的解构值。
¥Set resolved to the destructured value of the result of PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, defaultConditions).
否则,
¥Otherwise,
注意:说明符现在是一个裸说明符。
¥Note: specifier is now a bare specifier.
设置解析 PACKAGE_RESOLVE(specifier,parentURL) 的结果。
¥Set resolved the result of PACKAGE_RESOLVE(specifier, parentURL).
让格式未定义。
¥Let format be undefined.
如果解析的是 "file:" URL,则
¥If resolved is a "file:" URL, then
如果已解析包含 "/" 或 ""(分别为 "%2F" 和 "%5C")的任何百分比编码,则
¥If resolved contains any percent encodings of "/" or "" ("%2F" and "%5C" respectively), then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
如果解析的文件是一个目录,那么
¥If the file at resolved is a directory, then
引发不支持的目录导入错误。
¥Throw an Unsupported Directory Import error.
如果已解析的文件不存在,则
¥If the file at resolved does not exist, then
抛出模块未找到错误。
¥Throw a Module Not Found error.
设置 resolved 为 resolved 的真实路径,保持相同的 URL querystring 和 fragment 组件。
¥Set resolved to the real path of resolved, maintaining the same URL querystring and fragment components.
将格式设置为 ESM_FILE_FORMAT(resolved) 的结果。
¥Set format to the result of ESM_FILE_FORMAT(resolved).
否则,
¥Otherwise,
设置格式与解析的 URL 关联的内容类型的模块格式。
¥Set format the module format of the content type associated with the URL resolved.
加载解析为模块格式,格式。
¥Load resolved as module format, format.
PACKAGE_RESOLVE(packageSpecifier, parentURL)
让 packageName 未定义。
¥Let packageName be undefined.
如果 packageSpecifier 是空字符串,则
¥If packageSpecifier is an empty string, then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
如果 packageSpecifier 是 Node.js 内置模块名称,则
¥If packageSpecifier is a Node.js builtin module name, then
返回与 packageSpecifier 连接的字符串 "node:"。
¥Return the string "node:" concatenated with packageSpecifier.
如果 packageSpecifier 不以 "@" 开头,则
¥If packageSpecifier does not start with "@", then
将 packageName 设置为 packageSpecifier 的子字符串,直到第一个 "/" 分隔符或字符串的结尾。
¥Set packageName to the substring of packageSpecifier until the first "/" separator or the end of the string.
否则,
¥Otherwise,
如果 packageSpecifier 不包含 "/" 分隔符,则
¥If packageSpecifier does not contain a "/" separator, then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
将 packageName 设置为 packageSpecifier 的子字符串,直到第二个 "/" 分隔符或字符串的末尾。
¥Set packageName to the substring of packageSpecifier until the second "/" separator or the end of the string.
如果 packageName 以 "." 开头或包含 "" 或 "%",则
¥If packageName starts with "." or contains "" or "%", then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
让 packageSubpath "." 与 packageSpecifier 的子字符串从 packageName 长度的位置连接起来。
¥Let packageSubpath be "." concatenated with the substring of packageSpecifier from the position at the length of packageName.
如果 packageSubpath 以 "/" 结尾,则
¥If packageSubpath ends in "/", then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
令 selfUrl 为 PACKAGE_SELF_RESOLVE(packageName, packageSubpath, ParentURL) 的结果。
¥Let selfUrl be the result of PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL).
如果 selfUrl 不是未定义,则返回 selfUrl。
¥If selfUrl is not undefined, return selfUrl.
虽然 parentURL 不是文件系统根目录,
¥While parentURL is not the file system root,
令 packageURL 为 "node_modules/" 的 URL 解析与 packageSpecifier 连接,相对于 parentURL。
¥Let packageURL be the URL resolution of "node_modules/" concatenated with packageSpecifier, relative to parentURL.
将 parentURL 设置为 parentURL 的父文件夹 URL。
¥Set parentURL to the parent folder URL of parentURL.
如果 packageURL 处的文件夹不存在,则
¥If the folder at packageURL does not exist, then
继续下一个循环迭代。
¥Continue the next loop iteration.
令 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
¥Let pjson be the result of READ_PACKAGE_JSON(packageURL).
如果 pjson 不为 null 并且 pjson.exports 不为 null 或未定义,则
¥If pjson is not null and pjson.exports is not null or undefined, then
返回 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 的结果。
¥Return the result of PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions).
否则,如果 packageSubpath 等于 ".",则
¥Otherwise, if packageSubpath is equal to ".", then
如果 pjson.main 是一个字符串,那么
¥If pjson.main is a string, then
返回 packageURL 中 main 的 URL 解析。
¥Return the URL resolution of main in packageURL.
否则,
¥Otherwise,
返回 packageURL 中 packageSubpath 的 URL 解析。
¥Return the URL resolution of packageSubpath in packageURL.
抛出模块未找到错误。
¥Throw a Module Not Found error.
PACKAGE_SELF_RESOLVE(packageName, packageSubpath, parentURL)
令 packageURL 为 LOOKUP_PACKAGE_SCOPE(parentURL) 的结果。
¥Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(parentURL).
如果 packageURL 为 null,则
¥If packageURL is null, then
返回未定义。
¥Return undefined.
令 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
¥Let pjson be the result of READ_PACKAGE_JSON(packageURL).
如果 pjson 为 null 或者 pjson.exports 为 null 或未定义,则
¥If pjson is null or if pjson.exports is null or undefined, then
返回未定义。
¥Return undefined.
如果 pjson.name 等于 packageName,则
¥If pjson.name is equal to packageName, then
返回 PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions) 结果的解析解构值。
¥Return the resolved destructured value of the result of PACKAGE_EXPORTS_RESOLVE(packageURL, packageSubpath, pjson.exports, defaultConditions).
否则,返回未定义。
¥Otherwise, return undefined.
PACKAGE_EXPORTS_RESOLVE(packageURL, subpath, exports, conditions)
如果 exports 是一个对象,其键值以 "." 开头,键值不以 "." 开头,则抛出无效包配置错误。
¥If exports is an Object with both a key starting with "." and a key not starting with ".", throw an Invalid Package Configuration error.
如果子路径等于 ".",则
¥If subpath is equal to ".", then
让 mainExport 未定义。
¥Let mainExport be undefined.
如果导出是字符串或数组,或者不包含以 "." 开头的键的对象,则
¥If exports is a String or Array, or an Object containing no keys starting with ".", then
将 mainExport 设置为导出。
¥Set mainExport to exports.
否则,如果导出是包含 "." 属性的对象,则
¥Otherwise if exports is an Object containing a "." property, then
将 mainExport 设置为导出 ["."]。
¥Set mainExport to exports["."].
如果 mainExport 不是未定义的,那么
¥If mainExport is not undefined, then
令已解析为 PACKAGE_TARGET_RESOLVE(packageURL, mainExport, "", false, false, criteria) 的结果。
¥Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, mainExport, "", false, false, conditions).
如果已解决不为空或未定义,则
¥If resolved is not null or undefined, then
返回解决。
¥Return resolved.
否则,如果 exports 是一个 Object 并且 exports 的所有 key 都以 "." 开头,那么
¥Otherwise, if exports is an Object and all keys of exports start with ".", then
令 matchKey 为与子路径连接的字符串 "./"。
¥Let matchKey be the string "./" concatenated with subpath.
让 resolvedMatch 成为 PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey,exports,packageURL,false,conditions)的结果。
¥Let resolvedMatch be result of PACKAGE_IMPORTS_EXPORTS_RESOLVE( matchKey, exports, packageURL, false, conditions).
如果 resolvedMatch.resolve 不为 null 或未定义,则
¥If resolvedMatch.resolve is not null or undefined, then
返回解决匹配。
¥Return resolvedMatch.
抛出包路径未导出错误。
¥Throw a Package Path Not Exported error.
PACKAGE_IMPORTS_RESOLVE(specifier, parentURL, conditions)
断言:说明符以 "" 开头。
¥Assert: specifier begins with "#".
如果说明符完全等于 "" 或以 "#/" 开头,则
¥If specifier is exactly equal to "#" or starts with "#/", then
抛出无效的模块说明符错误。
¥Throw an Invalid Module Specifier error.
令 packageURL 为 LOOKUP_PACKAGE_SCOPE(parentURL) 的结果。
¥Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(parentURL).
如果 packageURL 不为 null,则
¥If packageURL is not null, then
令 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
¥Let pjson be the result of READ_PACKAGE_JSON(packageURL).
如果 pjson.imports 是一个非空对象,那么
¥If pjson.imports is a non-null Object, then
让 resolvedMatch 成为 PACKAGE_IMPORTS_EXPORTS_RESOLVE(specifier, pjson.imports, packageURL, true, Conditions)的结果。
¥Let resolvedMatch be the result of PACKAGE_IMPORTS_EXPORTS_RESOLVE(specifier, pjson.imports, packageURL, true, conditions).
如果 resolvedMatch.resolve 不为 null 或未定义,则
¥If resolvedMatch.resolve is not null or undefined, then
返回解决匹配。
¥Return resolvedMatch.
抛出包导入未定义错误。
¥Throw a Package Import Not Defined error.
PACKAGE_IMPORTS_EXPORTS_RESOLVE(matchKey, matchObj, packageURL, isImports, conditions)
如果 matchKey 是 matchObj 的键并且不以 "/" 结尾或包含 "*",则
¥If matchKey is a key of matchObj and does not end in "/" or contain ""*, then
令 target 为 matchObj[matchKey] 的值。
¥Let target be the value of matchObj[matchKey].
令已解析为 PACKAGE_TARGET_RESOLVE(packageURL, target, "", false, isImports, Conditions) 的结果。
¥Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, target, "", false, isImports, conditions).
返回对象 { resolved, exact: true }。
¥Return the object { resolved, exact: true }.
令 expansionKeys 为 matchObj 的键列表,要么以 "/" 结尾,要么仅包含单个 "*",由排序函数 PATTERN_KEY_COMPARE 排序,该函数按特异性降序排列。
¥Let expansionKeys be the list of keys of matchObj either ending in "/" or containing only a single ""*, sorted by the sorting function PATTERN_KEY_COMPARE which orders in descending order of specificity.
对于 expansionKeys 中的每个密钥 expansionKey,执行
¥For each key expansionKey in expansionKeys, do
令 patternBase 为空。
¥Let patternBase be null.
如果 expansionKey 包含 "",则将 patternBase 设置为 expansionKey 的子字符串,但不包括第一个 "" 字符。
¥If expansionKey contains "", set patternBase to the substring of expansionKey up to but excluding the first "" character.
如果 patternBase 不为 null 并且 matchKey 以 patternBase 开头但不等于 patternBase,则
¥If patternBase is not null and matchKey starts with but is not equal to patternBase, then
如果 matchKey 以 "/" 结尾,则抛出 Invalid Module Specifier 错误。
¥If matchKey ends with "/", throw an Invalid Module Specifier error.
设 patternTrailer 是第一个 "*" 字符后索引中 expansionKey 的子串。
¥Let patternTrailer be the substring of expansionKey from the index after the first ""* character.
如果 patternTrailer 的长度为零,或者 matchKey 以 patternTrailer 结尾并且 matchKey 的长度大于或等于 expandationKey 的长度,则
¥If patternTrailer has zero length, or if matchKey ends with patternTrailer and the length of matchKey is greater than or equal to the length of expansionKey, then
令 target 为 matchObj[expansionKey] 的值。
¥Let target be the value of matchObj[expansionKey].
令 subpath 为 matchKey 的子字符串,从 patternBase 长度的索引开始,直到 matchKey 的长度减去 patternTrailer 的长度。
¥Let subpath be the substring of matchKey starting at the index of the length of patternBase up to the length of matchKey minus the length of patternTrailer.
令 resolved 为 PACKAGE_TARGET_RESOLVE(packageURL, target, subpath, true, isImports, Conditions) 的结果。
¥Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, target, subpath, true, isImports, conditions).
返回对象 { resolved, exact: true }。
¥Return the object { resolved, exact: true }.
否则,如果 patternBase 为空并且 matchKey 以 expandationKey 开头,则
¥Otherwise if patternBase is null and matchKey starts with expansionKey, then
令 target 为 matchObj[expansionKey] 的值。
¥Let target be the value of matchObj[expansionKey].
设 subpath 是从 expansionKey 长度的索引开始的 matchKey 的子字符串。
¥Let subpath be the substring of matchKey starting at the index of the length of expansionKey.
令 resolved 为 PACKAGE_TARGET_RESOLVE(packageURL, target, subpath, false, isImports, Conditions) 的结果。
¥Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, target, subpath, false, isImports, conditions).
返回对象 { resolved, exact: false }。
¥Return the object { resolved, exact: false }.
返回对象 { resolved: null, exact: true }。
¥Return the object { resolved: null, exact: true }.
PATTERN_KEY_COMPARE(keyA, keyB)
断言:keyA 以 "/" 结尾或仅包含一个 "*"。
¥Assert: keyA ends with "/" or contains only a single ""*.
断言:keyB 以 "/" 结尾或仅包含一个 "*"。
¥Assert: keyB ends with "/" or contains only a single ""*.
令 baseLengthA 为 "" 在 keyA 中的索引加一,如果 keyA 包含 "",否则为 keyA 的长度。
¥Let baseLengthA be the index of ""* in keyA plus one, if keyA contains ""*, or the length of keyA otherwise.
令 baseLengthB 为 "" 在 keyB 中的索引加一,如果 keyB 包含 "",否则为 keyB 的长度。
¥Let baseLengthB be the index of ""* in keyB plus one, if keyB contains ""*, or the length of keyB otherwise.
如果 baseLengthA 大于 baseLengthB,则返回 -1。
¥If baseLengthA is greater than baseLengthB, return -1.
如果 baseLengthB 大于 baseLengthA,则返回 1。
¥If baseLengthB is greater than baseLengthA, return 1.
如果 keyA 不包含 "*",则返回 1。
¥If keyA does not contain ""*, return 1.
如果 keyB 不包含 "*",则返回 -1。
¥If keyB does not contain ""*, return -1.
如果 keyA 的长度大于 keyB 的长度,返回-1。
¥If the length of keyA is greater than the length of keyB, return -1.
如果 keyB 的长度大于 keyA 的长度,则返回 1。
¥If the length of keyB is greater than the length of keyA, return 1.
返回 0。
¥Return 0.
PACKAGE_TARGET_RESOLVE(packageURL, target, subpath, pattern, internal, conditions)
如果目标是一个字符串,那么
¥If target is a String, then
如果模式为 false,子路径具有非零长度并且目标不以 "/" 结尾,则抛出无效模块说明符错误。
¥If pattern is false, subpath has non-zero length and target does not end with "/", throw an Invalid Module Specifier error.
如果目标不是以 "./" 开头,则
¥If target does not start with "./", then
如果内部为 true 并且目标不以 "../" 或 "/" 开头并且不是有效的 URL,则
¥If internal is true and target does not start with "../" or "/" and is not a valid URL, then
如果模式为真,那么
¥If pattern is true, then
返回 PACKAGE_RESOLVE(目标,其中 "*" 的每个实例都替换为子路径,packageURL + "/")。
¥Return PACKAGE_RESOLVE(target with every instance of ""* replaced by subpath, packageURL + "/").
返回 PACKAGE_RESOLVE(目标 + 子路径, packageURL + "/")。
¥Return PACKAGE_RESOLVE(target + subpath, packageURL + "/").
否则,抛出一个 Invalid Package Target 错误。
¥Otherwise, throw an Invalid Package Target error.
如果 "/" 或 "" 上的目标拆分在第一个段之后包含任何 "."、".." 或 "node_modules" 段,不区分大小写并包括百分比编码变体,则抛出无效包目标错误。
¥If target split on "/" or "" contains any ".", "..", or "node_modules" segments after the first segment, case insensitive and including percent encoded variants, throw an Invalid Package Target error.
令 resolvedTarget 为 packageURL 和 target 串联的 URL 解析。
¥Let resolvedTarget be the URL resolution of the concatenation of packageURL and target.
断言:solvedTarget 包含在 packageURL 中。
¥Assert: resolvedTarget is contained in packageURL.
如果 "/" 或 "" 上的子路径拆分包含任何 "."、".." 或 "node_modules" 段,不区分大小写并包括百分比编码变体,则抛出无效模块说明符错误。
¥If subpath split on "/" or "" contains any ".", "..", or "node_modules" segments, case insensitive and including percent encoded variants, throw an Invalid Module Specifier error.
如果模式为真,那么
¥If pattern is true, then
返回 resolvedTarget 的 URL 解析,其中 "*" 的每个实例都替换为子路径。
¥Return the URL resolution of resolvedTarget with every instance of ""* replaced with subpath.
否则,
¥Otherwise,
返回 subpath 和 resolvedTarget 串联的 URL 解析。
¥Return the URL resolution of the concatenation of subpath and resolvedTarget.
否则,如果 target 是非空对象,则
¥Otherwise, if target is a non-null Object, then
如果导出包含任何索引属性键,如 ECMA-262 6.1.7 数组索引 中所定义,则抛出无效包配置错误。
¥If exports contains any index property keys, as defined in ECMA-262 6.1.7 Array Index, throw an Invalid Package Configuration error.
对于目标的每个属性 p,按对象插入顺序为:
¥For each property p of target, in object insertion order as,
如果 p 等于 "default" 或条件包含 p 的条目,则
¥If p equals "default" or conditions contains an entry for p, then
设 targetValue 为 target 中 p 属性的值。
¥Let targetValue be the value of the p property in target.
令 resolved 为 PACKAGE_TARGET_RESOLVE(packageURL, targetValue, subpath,pattern,internal,conditions)的结果。
¥Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, targetValue, subpath, pattern, internal, conditions).
如果 resolved 等于 undefined,则继续循环。
¥If resolved is equal to undefined, continue the loop.
返回解决。
¥Return resolved.
返回未定义。
¥Return undefined.
否则,如果 target 是一个数组,那么
¥Otherwise, if target is an Array, then
如果 _target.length 为零,则返回 null。
¥If _target.length is zero, return null.
对于目标中的每个项目 targetValue,执行
¥For each item targetValue in target, do
令 resolved 为 PACKAGE_TARGET_RESOLVE(packageURL, targetValue, subpath,pattern,internal,conditions)的结果,在任何无效的包目标错误上继续循环。
¥Let resolved be the result of PACKAGE_TARGET_RESOLVE( packageURL, targetValue, subpath, pattern, internal, conditions), continuing the loop on any Invalid Package Target error.
如果 resolved 未定义,则继续循环。
¥If resolved is undefined, continue the loop.
返回解决。
¥Return resolved.
返回或抛出最后的后备解决方案 null 返回或错误。
¥Return or throw the last fallback resolution null return or error.
否则,如果 target 为 null,则返回 null。
¥Otherwise, if target is null, return null.
否则抛出一个 Invalid Package Target 错误。
¥Otherwise throw an Invalid Package Target error.
ESM_FILE_FORMAT(url)
断言:url 对应于现有文件。
¥Assert: url corresponds to an existing file.
如果 url 以 ".mjs" 结尾,则
¥If url ends in ".mjs", then
返回 "module"。
¥Return "module".
如果 url 以 ".cjs" 结尾,则
¥If url ends in ".cjs", then
返回 "commonjs"。
¥Return "commonjs".
如果 url 以 ".json" 结尾,则
¥If url ends in ".json", then
返回 "json"。
¥Return "json".
令 packageURL 为 LOOKUP_PACKAGE_SCOPE(url) 的结果。
¥Let packageURL be the result of LOOKUP_PACKAGE_SCOPE(url).
令 pjson 为 READ_PACKAGE_JSON(packageURL) 的结果。
¥Let pjson be the result of READ_PACKAGE_JSON(packageURL).
如果 pjson?.type 存在且为 "module",则
¥If pjson?.type exists and is "module", then
如果 url 以 ".js" 结尾,则
¥If url ends in ".js", then
返回 "module"。
¥Return "module".
抛出不支持的文件扩展名错误。
¥Throw an Unsupported File Extension error.
否则,
¥Otherwise,
抛出不支持的文件扩展名错误。
¥Throw an Unsupported File Extension error.
LOOKUP_PACKAGE_SCOPE(url)
让 scopeURL 为 url。
¥Let scopeURL be url.
虽然 scopeURL 不是文件系统根目录,
¥While scopeURL is not the file system root,
将 scopeURL 设置为 scopeURL 的父 URL。
¥Set scopeURL to the parent URL of scopeURL.
如果 scopeURL 以 "node_modules" 路径段结束,则返回 null。
¥If scopeURL ends in a "node_modules" path segment, return null.
设 pjsonURL 为 scopeURL 中 "package.json" 的解析。
¥Let pjsonURL be the resolution of "package.json" within scopeURL.
如果 pjsonURL 处的文件存在,则
¥if the file at pjsonURL exists, then
返回范围 URL。
¥Return scopeURL.
返回空值。
¥Return null.
READ_PACKAGE_JSON(packageURL)
设 pjsonURL 为 packageURL 中 "package.json" 的解析。
¥Let pjsonURL be the resolution of "package.json" within packageURL.
如果 pjsonURL 处的文件不存在,则
¥If the file at pjsonURL does not exist, then
返回空值。
¥Return null.
如果 packageURL 处的文件未解析为有效的 JSON,则
¥If the file at packageURL does not parse as valid JSON, then
抛出一个无效的包配置错误。
¥Throw an Invalid Package Configuration error.
在 pjsonURL 返回文件的已解析 JSON 源。
¥Return the parsed JSON source of the file at pjsonURL.
自定义 ESM 说明符解析算法#
¥Customizing ESM specifier resolution algorithm
¥Stability: 1 - Experimental
不要依赖这个标志。我们计划在 加载器 API 改进到可以通过自定义加载程序实现等效功能的程度后将其删除。
¥Do not rely on this flag. We plan to remove it once the Loaders API has advanced to the point that equivalent functionality can be achieved via custom loaders.
当前说明符解析不支持 CommonJS 加载器的所有默认行为。行为差异之一是文件扩展名的自动解析以及导入具有索引文件的目录的能力。
¥The current specifier resolution does not support all default behavior of the CommonJS loader. One of the behavior differences is automatic resolution of file extensions and the ability to import directories that have an index file.
--experimental-specifier-resolution=[mode]
标志可用于自定义扩展解析算法。默认模式是 explicit
,它需要向加载程序提供模块的完整路径。要启用自动扩展解析并从包含索引文件的目录导入,请使用 node
模式。
¥The --experimental-specifier-resolution=[mode]
flag can be used to customize
the extension resolution algorithm. The default mode is explicit
, which
requires the full path to a module be provided to the loader. To enable the
automatic extension resolution and importing from directories that include an
index file use the node
mode.
$ node index.mjs
success!
$ node index # Failure!
Error: Cannot find module
$ node --experimental-specifier-resolution=node index
success!