Node.js v24.0.0 文档
- Node.js v24.0.0
- 目录
-
索引
- 断言测试
- 异步上下文跟踪
- 异步钩子
- Buffer
- C++ 插件
- 使用 Node-API 的 C/C++ 插件
- C++ 嵌入器 API
- 子进程
- 集群
- 命令行选项
- 控制台
- 加密
- 调试器
- 已弃用的 API
- 诊断通道
- DNS
- 域
- 错误
- 事件
- 文件系统
- 全局变量
- HTTP
- HTTP/2
- HTTPS
- 检查器
- 国际化
- 模块:CommonJS 模块
- 模块:ECMAScript 模块
- 模块:
node:module
API - 模块:包
- 模块:TypeScript
- Net
- OS
- Path
- 性能钩子
- 权限
- 进程
- Punycode
- 查询字符串
- Readline
- REPL
- 报告
- 单执行文件应用程序
- SQLite
- Stream
- 字符串解码器
- 测试运行器
- 定时器
- TLS/SSL
- 跟踪事件
- TTY
- UDP/数据报
- URL
- 实用工具
- V8
- VM
- WASI
- Web Crypto API
- Web Streams API
- Worker 线程
- Zlib
- 其他版本
- 选项
模块:包#
简介#
包是由 package.json
文件描述的文件夹树。 该包由包含 package.json
文件的文件夹和所有子文件夹组成,直到包含另一个 package.json
文件的下一个文件夹,或名为 node_modules
的文件夹。
此页面为编写 package.json
文件的包作者提供指导,以及 Node.js 定义的 package.json
字段的参考。
确定模块系统#
简介#
当作为初始输入传递给 node
,或由 import
语句或 import()
表达式引用时,Node.js 会将以下内容视为 ES 模块
-
带有
.mjs
扩展名的文件。 -
当最近的父
package.json
文件包含值为"module"
的顶级"type"
字段时,带有.js
扩展名的文件。 -
作为参数传递给
--eval
的字符串,或通过STDIN
管道传递给node
的字符串,带有标志--input-type=module
。 -
包含仅作为 ES 模块 成功解析的语法的代码,例如
import
或export
语句或import.meta
,没有关于应如何解释它的明确标记。 显式标记是.mjs
或.cjs
扩展名,具有"module"
或"commonjs"
值的package.json
"type"
字段,或--input-type
标志。 动态import()
表达式在 CommonJS 或 ES 模块中都支持,并且不会强制将文件视为 ES 模块。 参见 语法检测。
当作为初始输入传递给 node
,或由 import
语句或 import()
表达式引用时,Node.js 会将以下内容视为 CommonJS
-
带有
.cjs
扩展名的文件。 -
当最近的父
package.json
文件包含值为"commonjs"
的顶级字段"type"
时,带有.js
扩展名的文件。 -
作为参数传递给
--eval
或--print
的字符串,或通过STDIN
管道传递给node
的字符串,带有标志--input-type=commonjs
。 -
没有父
package.json
文件的带有.js
扩展名的文件,或者最近的父package.json
文件缺少type
字段,并且代码可以作为 CommonJS 成功求值。 换句话说,Node.js 首先尝试将此类“不明确”的文件作为 CommonJS 运行,如果作为 CommonJS 的求值失败,因为它发现 ES 模块语法,它将重试将它们作为 ES 模块求值。
在“不明确”文件中编写 ES 模块语法会产生性能成本,因此鼓励作者尽可能明确。 特别是,包作者应始终在其 package.json
文件中包含 "type"
字段,即使在所有源都是 CommonJS 的包中也是如此。 明确包的 type
将使包在 Node.js 的默认类型发生更改时具有面向未来的特性,并且它还会使构建工具和加载器更容易确定应如何解释包中的文件。
语法检测#
Node.js 将检查不明确输入的源代码,以确定它是否包含 ES 模块语法; 如果检测到此类语法,则该输入将被视为 ES 模块。
不明确的输入定义为
- 带有
.js
扩展名或没有扩展名的文件; 并且没有控制package.json
文件或缺少type
字段的文件。 - 当未指定
--input-type
时,字符串输入(--eval
或STDIN
)。
ES 模块语法定义为在作为 CommonJS 求值时会抛出的语法。 这包括以下内容
import
语句(但不是import()
表达式,这在 CommonJS 中有效)。export
语句。import.meta
引用。- 在模块顶层的
await
。 - CommonJS 包装器变量(
require
、module
、exports
、__dirname
、__filename
)的词法重新声明。
模块加载器#
Node.js 有两个系统用于解析说明符和加载模块。
有 CommonJS 模块加载器
- 它是完全同步的。
- 它负责处理
require()
调用。 - 它是可猴子补丁的。
- 它支持文件夹作为模块。
- 在解析说明符时,如果找不到完全匹配项,它将尝试添加扩展名(
.js
、.json
,最后是.node
),然后尝试解析文件夹作为模块。 - 它将
.json
视为 JSON 文本文件。 .node
文件被解释为使用process.dlopen()
加载的已编译插件模块。- 它将缺少
.json
或.node
扩展名的所有文件视为 JavaScript 文本文件。 - 如果模块图是同步的(不包含顶层
await
),则只能使用它来从 CommonJS 模块加载 ECMAScript 模块。 当用于加载不是 ECMAScript 模块的 JavaScript 文本文件时,该文件将作为 CommonJS 模块加载。
有 ECMAScript 模块加载器
- 它是异步的,除非它用于加载
require()
的模块。 - 它负责处理
import
语句和import()
表达式。 - 它是不可猴子补丁的,可以使用加载器钩子进行自定义。
- 它不支持文件夹作为模块,目录索引(例如
'./startup/index.js'
)必须完全指定。 - 它不进行扩展名搜索。 当说明符是相对或绝对文件 URL 时,必须提供文件扩展名。
- 它可以加载 JSON 模块,但需要导入类型属性。
- 它只接受 JavaScript 文本文件的
.js
、.mjs
和.cjs
扩展名。 - 它可用于加载 JavaScript CommonJS 模块。 此类模块通过
cjs-module-lexer
传递,以尝试识别命名导出,如果可以通过静态分析确定它们,则可以使用它们。 导入的 CommonJS 模块将其 URL 转换为绝对路径,然后通过 CommonJS 模块加载器加载。
package.json
和文件扩展名#
在一个包中,package.json
的 "type"
字段定义了 Node.js 应该如何解释 .js
文件。如果 package.json
文件没有 "type"
字段,则 .js
文件被视为 CommonJS。
package.json
中 "type"
的值为 "module"
时,告诉 Node.js 将该包中的 .js
文件解释为使用 ES 模块 语法。
"type"
字段不仅适用于初始入口点 (node my-app.js
),还适用于 import
语句和 import()
表达式引用的文件。
// my-app.js, treated as an ES module because there is a package.json
// file in the same folder with "type": "module".
import './startup/init.js';
// Loaded as ES module since ./startup contains no package.json file,
// and therefore inherits the "type" value from one level up.
import 'commonjs-package';
// Loaded as CommonJS since ./node_modules/commonjs-package/package.json
// lacks a "type" field or contains "type": "commonjs".
import './node_modules/commonjs-package/index.js';
// Loaded as CommonJS since ./node_modules/commonjs-package/package.json
// lacks a "type" field or contains "type": "commonjs".
无论最接近的父级 package.json
如何,以 .mjs
结尾的文件始终作为 ES 模块 加载。
无论最接近的父级 package.json
如何,以 .cjs
结尾的文件始终作为 CommonJS 加载。
import './legacy-file.cjs';
// Loaded as CommonJS since .cjs is always loaded as CommonJS.
import 'commonjs-package/src/index.mjs';
// Loaded as ES module since .mjs is always loaded as ES module.
.mjs
和 .cjs
扩展名可用于在同一包中混合类型
--input-type
标志#
当设置了 --input-type=module
标志时,作为参数传递给 --eval
(或 -e
) 的字符串,或通过 STDIN
管道传递给 node
的字符串,将被视为 ES 模块。
node --input-type=module --eval "import { sep } from 'node:path'; console.log(sep);"
echo "import { sep } from 'node:path'; console.log(sep);" | node --input-type=module
为了完整起见,还有 --input-type=commonjs
,用于显式地将字符串输入作为 CommonJS 运行。如果未指定 --input-type
,这是默认行为。
包入口点#
在一个包的 package.json
文件中,两个字段可以定义包的入口点:"main"
和 "exports"
。这两个字段都适用于 ES 模块和 CommonJS 模块入口点。
"main"
字段在所有 Node.js 版本中都受支持,但其功能有限:它只定义了包的主要入口点。
"exports"
提供了一个替代 "main"
的现代方式,允许定义多个入口点,支持环境之间的条件入口解析,并**防止任何其他入口点,除了在 "exports"
中定义的那些**。这种封装允许模块作者清楚地定义其包的公共接口。
对于针对当前支持的 Node.js 版本的新包,建议使用 "exports"
字段。 对于支持 Node.js 10 及更低版本的包,需要 "main"
字段。 如果同时定义了 "exports"
和 "main"
,则在支持的 Node.js 版本中,"exports"
字段优先于 "main"
。
条件导出可以在 "exports"
中使用,以定义每个环境的不同包入口点,包括包是通过 require
还是通过 import
引用。 有关在单个包中支持 CommonJS 和 ES 模块的更多信息,请查阅双 CommonJS/ES 模块包部分。
引入 "exports"
字段的现有包将阻止包的使用者使用任何未定义的入口点,包括 package.json
(例如,require('your-package/package.json')
)。这很可能是一个重大更改。
为了使 "exports"
的引入不造成重大更改,请确保导出每个先前支持的入口点。 最好显式指定入口点,以便很好地定义包的公共 API。 例如,一个先前导出 main
、lib
、feature
和 package.json
的项目可以使用以下 package.exports
{
"name": "my-package",
"exports": {
".": "./lib/index.js",
"./lib": "./lib/index.js",
"./lib/index": "./lib/index.js",
"./lib/index.js": "./lib/index.js",
"./feature": "./feature/index.js",
"./feature/index": "./feature/index.js",
"./feature/index.js": "./feature/index.js",
"./package.json": "./package.json"
}
}
或者,一个项目可以选择同时导出带有和不带有扩展子路径的整个文件夹,使用导出模式
{
"name": "my-package",
"exports": {
".": "./lib/index.js",
"./lib": "./lib/index.js",
"./lib/*": "./lib/*.js",
"./lib/*.js": "./lib/*.js",
"./feature": "./feature/index.js",
"./feature/*": "./feature/*.js",
"./feature/*.js": "./feature/*.js",
"./package.json": "./package.json"
}
}
在为任何次要包版本提供向后兼容性之后,包未来的主要更改可以正确地将导出限制为仅公开的特定功能导出
{
"name": "my-package",
"exports": {
".": "./lib/index.js",
"./feature/*.js": "./feature/*.js",
"./feature/internal/*": null
}
}
主入口点导出#
编写新包时,建议使用 "exports"
字段
{
"exports": "./index.js"
}
定义 "exports"
字段后,将封装包的所有子路径,并且导入者不再可使用这些子路径。 例如,require('pkg/subpath.js')
会抛出一个 ERR_PACKAGE_PATH_NOT_EXPORTED
错误。
此导出封装为工具提供了关于包接口的更可靠保证,并在处理包的 semver 升级时提供了更可靠的保证。 它不是一个强大的封装,因为直接 require 包的任何绝对子路径(例如 require('/path/to/node_modules/pkg/subpath.js')
)仍将加载 subpath.js
。
所有当前支持的 Node.js 版本和现代构建工具都支持 "exports"
字段。 对于使用旧版本 Node.js 或相关构建工具的项目,可以通过将 "main"
字段与 "exports"
一起包含来指向同一模块来实现兼容性
{
"main": "./index.js",
"exports": "./index.js"
}
子路径导出#
使用 "exports"
字段时,可以通过将主入口点视为 "."
子路径来定义自定义子路径
{
"exports": {
".": "./index.js",
"./submodule.js": "./src/submodule.js"
}
}
现在,使用者只能导入 "exports"
中定义的子路径
import submodule from 'es-module-package/submodule.js';
// Loads ./node_modules/es-module-package/src/submodule.js
而其他子路径将出错
import submodule from 'es-module-package/private-module.js';
// Throws ERR_PACKAGE_PATH_NOT_EXPORTED
子路径中的扩展名#
包作者应在其导出中提供带扩展名 (import 'pkg/subpath.js'
) 或不带扩展名 (import 'pkg/subpath'
) 的子路径。 这确保了每个导出的模块只有一个子路径,以便所有依赖项都导入相同的统一说明符,从而保持包契约对使用者清晰,并简化包子路径完成。
传统上,包倾向于使用不带扩展名的样式,该样式具有可读性和屏蔽包中文件真实路径的优点。
由于 导入映射现在为浏览器和其他 JavaScript 运行时中的包解析提供了一个标准,因此使用不带扩展名的样式可能会导致导入映射定义膨胀。 显式文件扩展名可以通过允许导入映射利用 包文件夹映射在可能的情况下映射多个子路径,而不是每个包子路径导出单独的映射条目,从而避免此问题。 这也镜像了在相对和绝对导入说明符中使用完整说明符路径的要求。
导出糖#
如果 "."
导出是唯一的导出,则 "exports"
字段为此情况提供了糖,是直接的 "exports"
字段值。
{
"exports": {
".": "./index.js"
}
}
可以写成
{
"exports": "./index.js"
}
子路径导入#
除了 "exports"
字段之外,还有一个包 "imports"
字段,用于创建仅适用于包本身内部的导入说明符的私有映射。
"imports"
字段中的条目必须始终以 #
开头,以确保它们与外部包说明符区分开来。
例如,可以使用 imports 字段来获得条件导出的好处用于内部模块
// package.json
{
"imports": {
"#dep": {
"node": "dep-node-native",
"default": "./dep-polyfill.js"
}
},
"dependencies": {
"dep-node-native": "^1.0.0"
}
}
其中 import '#dep'
不会获得外部包 dep-node-native
的解析(包括其 exports),而是在其他环境中获得相对于包的本地文件 ./dep-polyfill.js
。
与 "exports"
字段不同,"imports"
字段允许映射到外部包。
否则,imports 字段的解析规则与 exports 字段类似。
子路径模式#
对于导出或导入数量较少的包,我们建议显式列出每个导出子路径条目。 但是对于具有大量子路径的包,这可能会导致 package.json
膨胀和维护问题。
对于这些用例,可以使用子路径导出模式代替
// ./node_modules/es-module-package/package.json
{
"exports": {
"./features/*.js": "./src/features/*.js"
},
"imports": {
"#internal/*.js": "./src/internal/*.js"
}
}
*
映射公开嵌套的子路径,因为它只是一个字符串替换语法。
右侧的所有 *
实例都将被替换为此值,包括如果它包含任何 /
分隔符。
import featureX from 'es-module-package/features/x.js';
// Loads ./node_modules/es-module-package/src/features/x.js
import featureY from 'es-module-package/features/y/y.js';
// Loads ./node_modules/es-module-package/src/features/y/y.js
import internalZ from '#internal/z.js';
// Loads ./node_modules/es-module-package/src/internal/z.js
这是一个直接的静态匹配和替换,没有任何特殊的文件扩展名处理。 在映射的两侧包含 "*.js"
会将公开的包导出限制为仅 JS 文件。
由于可以通过将右侧目标模式视为针对包中文件列表的 **
glob 来确定软件包的各个导出,因此导出的静态可枚举属性通过导出模式来维护。 由于 node_modules
路径在导出目标中被禁止,因此这种扩展仅依赖于软件包本身的文件。
要从模式中排除私有子文件夹,可以使用 null
目标。
// ./node_modules/es-module-package/package.json
{
"exports": {
"./features/*.js": "./src/features/*.js",
"./features/private-internal/*": null
}
}
import featureInternal from 'es-module-package/features/private-internal/m.js';
// Throws: ERR_PACKAGE_PATH_NOT_EXPORTED
import featureX from 'es-module-package/features/x.js';
// Loads ./node_modules/es-module-package/src/features/x.js
条件导出#
条件导出提供了一种根据特定条件映射到不同路径的方法。 CommonJS 和 ES 模块导入都支持它们。
例如,一个想要为 require()
和 import
提供不同 ES 模块导出的包可以这样编写
// package.json
{
"exports": {
"import": "./index-module.js",
"require": "./index-require.cjs"
},
"type": "module"
}
Node.js 实现了以下条件,按从最具体到最不具体的顺序排列,因为应该定义条件
"node-addons"
- 类似于"node"
,并且匹配任何 Node.js 环境。 此条件可用于提供使用本机 C++ 插件的入口点,而不是更通用且不依赖本机插件的入口点。 可以通过--no-addons
标志禁用此条件。"node"
- 匹配任何 Node.js 环境。 可以是 CommonJS 或 ES 模块文件。 *在大多数情况下,显式调用 Node.js 平台是不必要的。*"import"
- 当通过import
或import()
加载包时,或者通过 ECMAScript 模块加载器的任何顶级导入或解析操作加载包时匹配。 适用于目标文件的模块格式。 *始终与"require"
互斥。*"require"
- 当通过require()
加载包时匹配。 引用文件应该可以用require()
加载,尽管该条件匹配与目标文件的模块格式无关。 预期格式包括 CommonJS、JSON、本机插件和 ES 模块。 *始终与"import"
互斥。*"module-sync"
- 无论包是通过import
、import()
还是require()
加载,都会匹配。 格式应为 ES 模块,其模块图中不包含顶级 await - 如果包含,则在require()
模块时将抛出ERR_REQUIRE_ASYNC_MODULE
。"default"
- 始终匹配的通用回退。 可以是 CommonJS 或 ES 模块文件。 *此条件应始终放在最后。*
在 "exports"
对象中,键的顺序非常重要。 在条件匹配期间,较早的条目具有更高的优先级,并且优先于后面的条目。 *一般规则是条件应该按照从最具体到最不具体的对象顺序排列*。
使用 "import"
和 "require"
条件可能会导致一些危险,这将在 双 CommonJS/ES 模块包部分中进一步解释。
"node-addons"
条件可用于提供使用本机 C++ 插件的入口点。 但是,可以通过 --no-addons
标志禁用此条件。 使用 "node-addons"
时,建议将 "default"
视为增强功能,可提供更通用的入口点,例如使用 WebAssembly 而不是本机插件。
条件导出也可以扩展到导出子路径,例如
{
"exports": {
".": "./index.js",
"./feature.js": {
"node": "./feature-node.js",
"default": "./feature.js"
}
}
}
定义一个包,其中 require('pkg/feature.js')
和 import 'pkg/feature.js'
可以在 Node.js 和其他 JS 环境之间提供不同的实现。
使用环境分支时,尽可能始终包含 "default"
条件。 提供 "default"
条件可确保任何未知的 JS 环境都能够使用此通用实现,这有助于避免这些 JS 环境不得不假装是现有环境才能支持具有条件导出的包。 因此,使用 "node"
和 "default"
条件分支通常比使用 "node"
和 "browser"
条件分支更可取。
嵌套条件#
除了直接映射之外,Node.js 还支持嵌套条件对象。
例如,要定义一个仅具有双模式入口点以用于 Node.js 而非浏览器的包
{
"exports": {
"node": {
"import": "./feature-node.mjs",
"require": "./feature-node.cjs"
},
"default": "./feature.mjs"
}
}
条件继续按照与平面条件相同的顺序匹配。 如果嵌套条件没有任何映射,它将继续检查父条件的剩余条件。 通过这种方式,嵌套条件的行为类似于嵌套 JavaScript if
语句。
解析用户条件#
运行 Node.js 时,可以使用 --conditions
标志添加自定义用户条件
node --conditions=development index.js
这将解析包导入和导出中的 "development"
条件,同时适当地解析现有的 "node"
、"node-addons"
、"default"
、"import"
和 "require"
条件。
可以使用重复标志设置任意数量的自定义条件。
典型条件应仅包含字母数字字符,必要时使用 ":"、"-" 或 "=" 作为分隔符。 任何其他字符都可能在 node 之外遇到兼容性问题。
在 node 中,条件几乎没有限制,但特别包括
- 它们必须包含至少一个字符。
- 它们不能以 "." 开头,因为它们可能会出现在也允许相对路径的位置。
- 它们不能包含 ",",因为某些 CLI 工具可能会将其解析为逗号分隔的列表。
- 它们不能是像 "10" 这样的整数属性键,因为这可能会对 JS 对象的属性键排序产生意外影响。
社区条件定义#
除了 "import"
、"require"
、"node"
、"module-sync"
、"node-addons"
和 "default"
条件之外的条件字符串,在 Node.js 核心中实现 默认情况下会被忽略。
其他平台可能会实现其他条件,并且可以通过 --conditions
/ -C
标志在 Node.js 中启用用户条件。
由于自定义包条件需要明确的定义以确保正确使用,因此下面提供了一个常见的已知包条件及其严格定义的列表,以协助生态系统协调。
"types"
- 可供类型系统用于解析给定导出的类型文件。 *此条件应始终首先包含。*"browser"
- 任何 Web 浏览器环境。"development"
- 可用于定义仅限开发的条目点,例如在开发模式下运行时提供额外的调试上下文,例如更好的错误消息。 *必须始终与"production"
互斥。*"production"
- 可用于定义生产环境条目点。 *必须始终与"development"
互斥。*
对于其他运行时,特定于平台的条件键定义由 WinterCG 在 运行时键提案规范中维护。
可以通过创建一个拉取请求到 此部分的 Node.js 文档,将新的条件定义添加到此列表。 列出新条件定义的要求是
- 该定义对于所有实施者都应清晰明确。
- 应明确证明需要该条件的原因。
- 应该存在足够的现有实施用法。
- 条件名称不应与另一个条件定义或广泛使用的条件冲突。
- 条件定义的列出应为生态系统提供协调效益,否则将无法实现。 例如,对于特定于公司或特定于应用程序的条件,情况并非如此。
- 该条件应该是 Node.js 用户期望它出现在 Node.js 核心文档中的条件。
"types"
条件就是一个很好的例子:它实际上不属于 运行时键提案,但非常适合 Node.js 文档。
上述定义可能会在适当的时候迁移到专用的条件注册表。
使用其名称自引用包#
在一个包中,可以通过包的名称引用包的 package.json
"exports"
字段中定义的值。 例如,假设 package.json
是
// package.json
{
"name": "a-package",
"exports": {
".": "./index.mjs",
"./foo.js": "./foo.js"
}
}
然后,任何模块*在该包中*都可以引用包本身的导出
// ./a-module.mjs
import { something } from 'a-package'; // Imports "something" from ./index.mjs.
仅当 package.json
具有 "exports"
时,自引用才可用,并且仅允许导入该 "exports"
(在 package.json
中)允许的内容。 因此,给定先前包的以下代码将生成运行时错误
// ./another-module.mjs
// Imports "another" from ./m.mjs. Fails because
// the "package.json" "exports" field
// does not provide an export named "./m.mjs".
import { another } from 'a-package/m.mjs';
在使用 require
时,无论是在 ES 模块中还是在 CommonJS 模块中,自引用也可用。 例如,此代码也将有效
// ./a-module.js
const { something } = require('a-package/foo.js'); // Loads from ./foo.js.
最后,自引用也适用于作用域包。 例如,此代码也将有效
// package.json
{
"name": "@my/package",
"exports": "./index.js"
}
// ./index.js
module.exports = 42;
// ./other.js
console.log(require('@my/package'));
$ node other.js
42
双 CommonJS/ES 模块包#
有关详细信息,请参见包示例存储库。
Node.js package.json
字段定义#
本节介绍 Node.js 运行时使用的字段。 其他工具(例如 npm)使用 Node.js 忽略的其他字段,并且此处未记录。
Node.js 中使用了 package.json
文件中的以下字段
"name"
- 在包中使用命名导入时相关。 也被包管理器用作包的名称。"main"
- 加载包时的默认模块,如果未指定 exports,并且在 Node.js 的早期版本(exports 引入之前)。"type"
- 包类型,决定了如何加载.js
文件,是作为 CommonJS 还是 ES 模块。"exports"
- 包导出和条件导出。 存在时,限制了可以从包中加载哪些子模块。"imports"
- 包导入,供包本身内的模块使用。
"main"
#
- 类型: <string>
{
"main": "./index.js"
}
"main"
字段定义了通过 node_modules
查找按名称导入包时的入口点。 它的值是一个路径。
当一个包具有 "exports"
字段时,通过名称导入包时,它将优先于 "main"
字段。
它还定义了当通过 require()
加载包目录时使用的脚本。
// This resolves to ./path/to/directory/index.js.
require('./path/to/directory');
"type"
#
- 类型: <string>
"type"
字段定义了 Node.js 用于所有 .js
文件的模块格式,这些文件将该 package.json
文件作为其最近的父级。
当最近的父级 package.json
文件包含一个值为 "module"
的顶级字段 "type"
时,以 .js
结尾的文件将作为 ES 模块加载。
最近的父级 package.json
被定义为在当前文件夹、该文件夹的父级等中搜索时找到的第一个 package.json
,直到到达 node_modules 文件夹或卷根目录。
// package.json
{
"type": "module"
}
# In same folder as preceding package.json
node my-app.js # Runs as ES module
如果最近的父级 package.json
缺少 "type"
字段,或者包含 "type": "commonjs"
,则 .js
文件被视为 CommonJS。 如果到达卷根目录且未找到 package.json
,则 .js
文件被视为 CommonJS。
如果最近的父级 package.json
包含 "type": "module"
,则 .js
文件的 import
语句被视为 ES 模块。
// my-app.js, part of the same example as above
import './startup.js'; // Loaded as ES module because of package.json
无论 "type"
字段的值如何,.mjs
文件始终被视为 ES 模块,而 .cjs
文件始终被视为 CommonJS。
"exports"
#
- 类型: <Object> | <string> | <string[]>
{
"exports": "./index.js"
}
当通过 node_modules
查找或自引用其自身的名称加载时,"exports"
字段允许定义通过名称导入的包的入口点。 它在 Node.js 12+ 中受支持,作为 "main"
的替代方案,它可以支持定义 子路径导出和条件导出,同时封装内部未导出的模块。
条件导出也可以在 "exports"
中使用,以定义每个环境的不同包入口点,包括包是通过 require
引用还是通过 import
引用。
"exports"
中定义的所有路径都必须是以 ./
开头的相对文件 URL。