条件导出
【Conditional exports】
条件导出提供了一种根据特定条件映射到不同路径的方式。它们同时支持 CommonJS 和 ES 模块导入。
【Conditional exports provide a way to map to different paths depending on certain conditions. They are supported for both CommonJS and ES module imports.】
例如,一个希望为 require() 和 import 提供不同 ES 模块导出的包可以这样编写:
【For example, a package that wants to provide different ES module exports for
require() and import can be written:】
// package.json
{
"exports": {
"import": "./index-module.js",
"require": "./index-require.cjs"
},
"type": "module"
} Node.js 实现了以下条件,按从最具体到最不具体的顺序列出,因为条件应如此定义:
【Node.js implements the following conditions, listed in order from most specific to least specific as conditions should be defined:】
"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" 对象中,键的顺序是重要的。在条件匹配过程中,较早的条目具有更高的优先级,优先于较晚的条目。一般规则是,条件应按照从最具体到最不具体的顺序排列在对象中。
【Within the "exports" object, key order is significant. During condition
matching, earlier entries have higher priority and take precedence over later
entries. The general rule is that conditions should be from most specific to
least specific in object order.】
使用 "import" 和 "require" 条件可能会导致一些风险,这些风险在 双重 CommonJS/ES 模块包部分 中有进一步解释。
【Using the "import" and "require" conditions can lead to some hazards,
which are further explained in the dual CommonJS/ES module packages section.】
"node-addons" 条件可以用来提供一个使用本地 C++ 插件的入口点。然而,该条件可以通过 --no-addons 标志 被禁用。在使用 "node-addons" 时,建议将 "default" 视为一种增强,提供一个更通用的入口点,例如使用 WebAssembly 代替本地插件。
【The "node-addons" condition can be used to provide an entry point which
uses native C++ addons. However, this condition can be disabled via the
--no-addons flag. When using "node-addons", it's recommended to treat
"default" as an enhancement that provides a more universal entry point, e.g.
using WebAssembly instead of a native addon.】
条件导出也可以扩展为导出子路径,例如:
【Conditional exports can also be extended to exports subpaths, for example:】
{
"exports": {
".": "./index.js",
"./feature.js": {
"node": "./feature-node.js",
"default": "./feature.js"
}
}
} 定义一个包,在该包中 require('pkg/feature.js') 和 import 'pkg/feature.js' 在 Node.js 与其他 JS 环境之间可能提供不同的实现。
【Defines a package where require('pkg/feature.js') and
import 'pkg/feature.js' could provide different implementations between
Node.js and other JS environments.】
在使用环境分支时,尽可能始终包含一个 "default" 条件。提供 "default" 条件可以确保任何未知的 JS 环境能够使用这个通用实现,这有助于避免这些 JS 环境为了支持具有条件导出的包而不得不假装成现有环境。因此,使用 "node" 和 "default" 条件分支通常比使用 "node" 和 "browser" 条件分支更可取。
【When using environment branches, always include a "default" condition where
possible. Providing a "default" condition ensures that any unknown JS
environments are able to use this universal implementation, which helps avoid
these JS environments from having to pretend to be existing environments in
order to support packages with conditional exports. For this reason, using
"node" and "default" condition branches is usually preferable to using
"node" and "browser" condition branches.】