包入口点#>
🌐 Package entry points
在一个包的 package.json 文件中,有两个字段可以定义包的入口点:"main" 和 "exports"。两个字段都适用于 ES 模块和 CommonJS 模块的入口点。
🌐 In a package's package.json file, two fields can define entry points for a
package: "main" and "exports". Both fields apply to both ES module
and CommonJS module entry points.
"main" 字段在所有版本的 Node.js 中都受到支持,但其功能有限:它仅定义了包的主要入口点。
🌐 The "main" field is supported in all versions of Node.js, but its
capabilities are limited: it only defines the main entry point of the package.
"exports" 提供了 "main" 的现代替代方案,允许定义多个入口点,支持在不同环境之间进行条件入口解析,并且防止使用除 "exports" 中定义的入口点之外的任何其他入口点。这种封装使模块作者能够清晰地定义他们包的公共接口。
🌐 The "exports" provides a modern alternative to "main" allowing
multiple entry points to be defined, conditional entry resolution support
between environments, and preventing any other entry points besides those
defined in "exports". This encapsulation allows module authors to
clearly define the public interface for their package.
对于面向当前支持的 Node.js 版本的新软件包,建议使用 "exports" 字段。对于支持 Node.js 10 及以下版本的软件包,必须使用 "main" 字段。如果同时定义了 "exports" 和 "main" 字段,则在支持的 Node.js 版本中,"exports" 字段优先于 "main" 字段。
🌐 For new packages targeting the currently supported versions of Node.js, the
"exports" field is recommended. For packages supporting Node.js 10 and
below, the "main" field is required. If both "exports" and
"main" are defined, the "exports" field takes precedence over
"main" in supported versions of Node.js.
条件导出 可以在 "exports" 中使用,以定义每个环境的不同包入口点,包括该包是通过 require 还是通过 import 引用。有关在单个包中同时支持 CommonJS 和 ES 模块的更多信息,请参阅 双重 CommonJS/ES 模块包部分。
引入 "exports" 字段的现有包将阻止包的使用者使用任何未定义的入口点,包括 package.json(例如 require('your-package/package.json'))。这很可能会是一个重大更改。
🌐 Existing packages introducing the "exports" field will prevent consumers
of the package from using any entry points that are not defined, including the
package.json (e.g. require('your-package/package.json')). This will
likely be a breaking change.
为了使 "exports" 的引入保持向后兼容,请确保导出之前支持的每个入口点。最好明确指定入口点,以便包的公共 API 定义清晰。例如,一个之前导出 main、lib、feature 和 package.json 的项目可以使用以下 package.exports:
🌐 To make the introduction of "exports" non-breaking, ensure that every
previously supported entry point is exported. It is best to explicitly specify
entry points so that the package's public API is well-defined. For example,
a project that previously exported main, lib,
feature, and the package.json could use the following 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"
}
} 拷贝
或者,一个项目可以选择使用导出模式导出整个文件夹,同时包含或不包含带扩展名的子路径:
🌐 Alternatively a project could choose to export entire folders both with and
without extensioned subpaths using export patterns:
{
"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"
}
} 拷贝
通过上述为任何次要版本提供向后兼容性,包的未来重大更改就可以适当地将导出限制为仅公开的特定功能导出:
🌐 With the above providing backwards-compatibility for any minor package versions,
a future major change for the package can then properly restrict the exports
to only the specific feature exports exposed:
{
"name": "my-package",
"exports": {
".": "./lib/index.js",
"./feature/*.js": "./feature/*.js",
"./feature/internal/*": null
}
} 拷贝
主入口点导出#>
🌐 Main entry point export
在编写新软件包时,建议使用 "exports" 字段:
🌐 When writing a new package, it is recommended to use the "exports" field:
{
"exports": "./index.js"
} 拷贝
当定义了 "exports" 字段时,包的所有子路径都会被封装,导入者将无法再访问。例如,require('pkg/subpath.js') 会抛出 ERR_PACKAGE_PATH_NOT_EXPORTED 错误。
🌐 When the "exports" field is defined, all subpaths of the package are
encapsulated and no longer available to importers. For example,
require('pkg/subpath.js') throws an ERR_PACKAGE_PATH_NOT_EXPORTED
error.
这种对导出的封装为工具以及在处理包的语义化版本升级时提供了更可靠的包接口保证。这不是一种强封装,因为对包的任何绝对子路径的直接 require,例如 require('/path/to/node_modules/pkg/subpath.js'),仍然会加载 subpath.js。
🌐 This encapsulation of exports provides more reliable guarantees
about package interfaces for tools and when handling semver upgrades for a
package. It is not a strong encapsulation since a direct require of any
absolute subpath of the package such as
require('/path/to/node_modules/pkg/subpath.js') will still load subpath.js.
所有目前支持的 Node.js 版本和现代构建工具都支持 "exports" 字段。对于使用较旧版本 Node.js 或相关构建工具的项目,可以通过在 "exports" 字段旁边包含 "main" 字段并指向同一个模块来实现兼容性:
🌐 All currently supported versions of Node.js and modern build tools support the
"exports" field. For projects using an older version of Node.js or a related
build tool, compatibility can be achieved by including the "main" field
alongside "exports" pointing to the same module:
{
"main": "./index.js",
"exports": "./index.js"
} 拷贝
子路径导出#>
🌐 Subpath exports
新增于: v12.7.0
在使用 "exports" 字段时,可以定义自定义子路径以及主入口点,通过将主入口点视为 "." 子路径来实现:
🌐 When using the "exports" field, custom subpaths can be defined along
with the main entry point by treating the main entry point as the
"." subpath:
{
"exports": {
".": "./index.js",
"./submodule.js": "./src/submodule.js"
}
} 拷贝
现在只有在 "exports" 中定义的子路径可以被使用者导入:
🌐 Now only the defined subpath in "exports" can be imported by a consumer:
import submodule from 'es-module-package/submodule.js';
// Loads ./node_modules/es-module-package/src/submodule.js 拷贝
而其他子路径会出错:
🌐 While other subpaths will error:
import submodule from 'es-module-package/private-module.js';
// Throws ERR_PACKAGE_PATH_NOT_EXPORTED 拷贝
子路径中的扩展#>
🌐 Extensions in subpaths
包的作者应该在其导出中提供带扩展名(import 'pkg/subpath.js')或不带扩展名(import 'pkg/subpath')的子路径。这确保每个导出模块只有一个子路径,从而使所有依赖方导入相同的一致的标识符,保持包的契约对使用者清晰,并简化包子路径的补全。
🌐 Package authors should provide either extensioned (import 'pkg/subpath.js') or
extensionless (import 'pkg/subpath') subpaths in their exports. This ensures
that there is only one subpath for each exported module so that all dependents
import the same consistent specifier, keeping the package contract clear for
consumers and simplifying package subpath completions.
传统上,包通常倾向于使用无扩展名的风格,这种风格具有可读性强以及隐藏包内文件真实路径的优点。
🌐 Traditionally, packages tended to use the extensionless style, which has the
benefits of readability and of masking the true path of the file within the
package.
随着 导入地图 现在为浏览器和其他 JavaScript 运行时提供了包解析的标准,使用无扩展名的风格可能会导致导入映射定义膨胀。显式的文件扩展名可以避免这个问题,因为它使导入映射能够利用 包文件夹映射 尽可能地映射多个子路径,而不必为每个包子路径导出创建单独的映射条目。这也反映了在相对和绝对导入说明符中使用 完整限定路径 的要求。
🌐 With import maps now providing a standard for package resolution in browsers
and other JavaScript runtimes, using the extensionless style can result in
bloated import map definitions. Explicit file extensions can avoid this issue by
enabling the import map to utilize a packages folder mapping to map multiple
subpaths where possible instead of a separate map entry per package subpath
export. This also mirrors the requirement of using the full specifier path
in relative and absolute import specifiers.
导出目标的路径规则和验证#>
🌐 Path Rules and Validation for Export Targets
在将路径定义为 "exports" 字段中的目标时,Node.js 会执行多项规则以确保安全性、可预测性和适当的封装。理解这些规则对于发布软件包的作者来说至关重要。
🌐 When defining paths as targets in the "exports" field, Node.js enforces
several rules to ensure security, predictability, and proper encapsulation.
Understanding these rules is crucial for authors publishing packages.
目标必须是相对 URL#>
🌐 Targets must be relative URLs
"exports" 地图中的所有目标路径(与导出键相关的值)必须是以 ./ 开头的相对 URL 字符串。
🌐 All target paths in the "exports" map (the values associated with export
keys) must be relative URL strings starting with ./.
// package.json
{
"name": "my-package",
"exports": {
".": "./dist/main.js", // Correct
"./feature": "./lib/feature.js", // Correct
// "./origin-relative": "/dist/main.js", // Incorrect: Must start with ./
// "./absolute": "file:///dev/null", // Incorrect: Must start with ./
// "./outside": "../common/util.js" // Incorrect: Must start with ./
}
} 拷贝
此行为的原因包括:
🌐 Reasons for this behavior include:
安全性: 防止从包自身目录之外导出任意文件。
封装: 确保所有导出的路径都相对于包根进行解析,使包成为自包含的。
无路径遍历或无效片段#>
🌐 No path traversal or invalid segments
导出目标不得解析到包根目录之外的位置。此外,在 target 字符串的初始 ./ 之后以及替换到目标模式中的任何 subpath 部分中,通常不允许出现像 .(单点)、..(双点)或 node_modules(及其 URL 编码等效项)这样的路径段。
🌐 Export targets must not resolve to a location outside the package's root
directory. Additionally, path segments like . (single dot), .. (double dot),
or node_modules (and their URL-encoded equivalents) are generally disallowed
within the target string after the initial ./ and in any subpath part
substituted into a target pattern.
// package.json
{
"name": "my-package",
"exports": {
// ".": "./dist/../../elsewhere/file.js", // Invalid: path traversal
// ".": "././dist/main.js", // Invalid: contains "." segment
// ".": "./dist/../dist/main.js", // Invalid: contains ".." segment
// "./utils/./helper.js": "./utils/helper.js" // Key has invalid segment
}
} 拷贝
导出糖#>
🌐 Exports sugar
新增于: v12.11.0
如果是'“。”导出是唯一的导出,"exports"田提供糖
对于此情况,则是直接的"exports"场值。
🌐 If the "." export is the only export, the "exports" field provides sugar
for this case being the direct "exports" field value.
{
"exports": {
".": "./index.js"
}
} 拷贝
可以写成:
🌐 can be written:
{
"exports": "./index.js"
} 拷贝
子路径导入#>
🌐 Subpath imports
新增于: v14.6.0, v12.19.0
除了"exports"字段外,还有一个包“导入”字段
创建仅适用于从
封装本身。
🌐 In addition to the "exports" field, there is a package "imports" field
to create private mappings that only apply to import specifiers from within the
package itself.
"imports" 字段中的条目必须始终以 # 开头,以确保它们与外部包说明符区分开来。
🌐 Entries in the "imports" field must always start with # to ensure they are
disambiguated from external package specifiers.
例如,imports 字段可以用于为内部模块获得条件导出的好处:
🌐 For example, the imports field can be used to gain the benefits of conditional
exports for internal modules:
// package.json
{
"imports": {
"#dep": {
"node": "dep-node-native",
"default": "./dep-polyfill.js"
}
},
"dependencies": {
"dep-node-native": "^1.0.0"
}
} 拷贝
当 import '#dep' 无法解析外部包 dep-node-native(包括其导出内容)时,它会在其他环境中获取相对于该包的本地文件 ./dep-polyfill.js。
🌐 where import '#dep' does not get the resolution of the external package
dep-node-native (including its exports in turn), and instead gets the local
file ./dep-polyfill.js relative to the package in other environments.
与 "exports" 字段不同,"imports" 字段允许映射到外部包。
🌐 Unlike the "exports" field, the "imports" field permits mapping to external
packages.
imports 字段的解析规则在其他方面与 exports 字段类似。
🌐 The resolution rules for the imports field are otherwise analogous to the
exports field.
子路径模式#>
🌐 Subpath patterns
版本历史
版本变更
v16.10.0, v14.19.0
Support pattern trailers in "imports" field.
v16.9.0, v14.19.0
Support pattern trailers.
v14.13.0, v12.20.0
新增于: v14.13.0, v12.20.0
对于导出或导入数量较少的包,我们建议显式列出每个 exports 子路径条目。但对于子路径数量较多的包,这可能会导致 package.json 文件变大并带来维护问题。
🌐 For packages with a small number of exports or imports, we recommend
explicitly listing each exports subpath entry. But for packages that have
large numbers of subpaths, this might cause package.json bloat and
maintenance issues.
对于这些用例,可以使用子路径导出模式:
🌐 For these use cases, subpath export patterns can be used instead:
// ./node_modules/es-module-package/package.json
{
"exports": {
"./features/*.js": "./src/features/*.js"
},
"imports": {
"#internal/*.js": "./src/internal/*.js"
}
} 拷贝
* 映射仅作为字符串替换语法暴露嵌套子路径。
右边所有的 * 实例都将被此值替换,包括其中包含任何 / 分隔符的情况。
🌐 All instances of * on the right hand side will then be replaced with this
value, including if it contains any / separators.
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 文件。
🌐 This is a direct static matching and replacement without any special handling
for file extensions. Including the "*.js" on both sides of the mapping
restricts the exposed package exports to only JS files.
通过导出模式,导出具有静态可枚举性的特性得以保持,因为可以通过将右侧的目标模式视为针对包内文件列表的 ** 通配符来确定包的各个导出。由于在导出目标中禁止使用 node_modules 路径,这种展开仅依赖于包自身的文件。
🌐 The property of exports being statically enumerable is maintained with exports
patterns since the individual exports for a package can be determined by
treating the right hand side target pattern as a ** glob against the list of
files within the package. Because node_modules paths are forbidden in exports
targets, this expansion is dependent on only the files of the package itself.
要从模式中排除私有子文件夹,可以使用 null 目标:
🌐 To exclude private subfolders from patterns, null targets can be used:
// ./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 拷贝
条件导出#>
🌐 Conditional exports
版本历史
版本变更
v13.7.0, v12.16.0
Unflag conditional exports.
v13.2.0, v12.16.0
新增于: v13.2.0, v12.16.0
条件导出提供了一种根据特定条件映射到不同路径的方式。它们同时支持 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.
嵌套条件#>
🌐 Nested conditions
除了直接映射,Node.js 还支持嵌套条件对象。
🌐 In addition to direct mappings, Node.js also supports nested condition objects.
例如,要定义一个只在 Node.js 中使用而不在浏览器中使用的具有双模式入口点的包:
🌐 For example, to define a package that only has dual mode entry points for
use in Node.js but not the browser:
{
"exports": {
"node": {
"import": "./feature-node.mjs",
"require": "./feature-node.cjs"
},
"default": "./feature.mjs"
}
} 拷贝
条件会按顺序继续匹配,就像平铺的条件一样。如果嵌套条件没有任何映射,它将继续检查父条件的其余条件。通过这种方式,嵌套条件的行为类似于嵌套的 JavaScript if 语句。
🌐 Conditions continue to be matched in order as with flat conditions. If
a nested condition does not have any mapping it will continue checking
the remaining conditions of the parent condition. In this way nested
conditions behave analogously to nested JavaScript if statements.
解析用户条件#>
🌐 Resolving user conditions
新增于: v14.9.0, v12.19.0
在运行 Node.js 时,可以使用 --conditions 标志添加自定义用户条件:
🌐 When running Node.js, custom user conditions can be added with the
--conditions flag:
node --conditions=development index.js 拷贝
这将会解决包导入和导出中的“development”条件,同时适当地解决现有的“node”、“node-addons”、“default”、“import”和“require”条件。
🌐 which would then resolve the "development" condition in package imports and
exports, while resolving the existing "node", "node-addons", "default",
"import", and "require" conditions as appropriate.
可以使用重复标志设置任意数量的自定义条件。
🌐 Any number of custom conditions can be set with repeat flags.
典型条件应仅包含字母数字字符,如果有必要,可以使用“:”、“-”或“=”作为分隔符。其他任何内容可能在节点外运行时出现兼容性问题。
🌐 Typical conditions should only contain alphanumerical characters,
using ":", "-", or "=" as separators if necessary. Anything else may run
into compability issues outside of node.
在节点中,条件几乎没有限制,但具体包括:
🌐 In node, conditions have very few restrictions, but specifically these include:
它们必须至少包含一个字符。
它们不能以“.”开头,因为它们可能出现在也允许相对路径的位置。
它们不能包含 ",",因为某些命令行工具可能会将其解析为以逗号分隔的列表。
它们不能像“10”那样是整数属性键,因为这可能对 JavaScript 对象的属性键排序产生意想不到的影响。
社区条件定义#>
🌐 Community Conditions Definitions
除“import”、“require”、“node”、“module-sync”、“node-addons”和“default”条件外,默认情况下会忽略Node.js 核心实现的其他条件字符串。
🌐 Condition strings other than the "import", "require", "node", "module-sync",
"node-addons" and "default" conditions
implemented in Node.js core are ignored by default.
其他平台可能会实现其他条件,并且可以通过 --conditions / -C 标志 在 Node.js 中启用用户条件。
🌐 Other platforms may implement other conditions and user conditions can be
enabled in Node.js via the --conditions / -C flag.
由于定制包的条件需要明确的定义以确保正确使用,以下提供了一份常见已知包条件及其严格定义的列表,以协助生态系统协调。
🌐 Since custom package conditions require clear definitions to ensure correct
usage, a list of common known package conditions and their strict definitions
is provided below to assist with ecosystem coordination.
"types" - 可以被类型系统用来解析给定导出的类型文件。此条件应始终首先包含。
"browser" - 任何网页浏览器环境。
"development" - 可以用于定义仅限开发环境的入口点,例如在开发模式下提供额外的调试信息,如更详细的错误消息。必须始终与 "production" 互斥。
"production" - 可用于定义生产环境入口点。必须始终与 "development" 互斥。
对于其他运行时,由 运行时密钥 提案规范中的 冬季CG 维护平台特定的条件键定义。
🌐 For other runtimes, platform-specific condition key definitions are maintained
by the WinterCG in the Runtime Keys proposal specification.
可以通过向 本节的 Node.js 文档 创建拉取请求将新的条件定义添加到此列表中。在此列出新条件定义的要求是:
🌐 New conditions definitions may be added to this list by creating a pull request
to the Node.js documentation for this section. The requirements for listing
a new condition definition here are that:
定义应当清晰明确,以便所有实现者都能理解。
需要明确说明为什么需要该条件的使用情况。
应该存在足够的现有实现使用。
条件名称不应与其他条件定义或广泛使用的条件冲突。
条件定义的列表应该为生态系统提供一种协调效益,而这是在其他情况下无法实现的。例如,公司特定或应用特定的条件不一定能够实现这种效果。
条件应该是符合 Node.js 用户在 Node.js 核心文档中所期望的。"types" 条件是一个很好的例子:它实际上并不属于 运行时密钥 提案,但在 Node.js 文档中非常合适。
上述定义可能会在适当的时候移至专门的条件登记处。
🌐 The above definitions may be moved to a dedicated conditions registry in due
course.
使用名称自引用包#>
🌐 Self-referencing a package using its name
版本历史
版本变更
v13.6.0, v12.16.0
Unflag self-referencing a package using its name.
v13.1.0, v12.16.0
新增于: v13.1.0, v12.16.0
在一个包中,可以通过包的名称引用在包的 package.json 的 "exports" 字段中定义的值。例如,假设 package.json 如下:
🌐 Within a package, the values defined in the package's
package.json "exports" field can be referenced via the package's name.
For example, assuming the package.json is:
// package.json
{
"name": "a-package",
"exports": {
".": "./index.mjs",
"./foo.js": "./foo.js"
}
} 拷贝
那么该包中的任何模块都可以引用包本身中的导出内容:
🌐 Then any module in that package can reference an export in the package itself:
// ./a-module.mjs
import { something } from 'a-package'; // Imports "something" from ./index.mjs. 拷贝
只有在 package.json 中有 "exports" 时才可以使用自引用,并且只允许导入该 "exports"(在 package.json 中)允许的内容。因此,以下代码在使用之前的包时,将会产生运行时错误:
🌐 Self-referencing is available only if package.json has "exports", and
will allow importing only what that "exports" (in the package.json)
allows. So the code below, given the previous package, will generate a runtime
error:
// ./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 模块中。例如,这段代码也可以正常运行:
🌐 Self-referencing is also available when using require, both in an ES module,
and in a CommonJS one. For example, this code will also work:
// ./a-module.js
const { something } = require('a-package/foo.js'); // Loads from ./foo.js. 拷贝
最后,自引用也适用于有作用域的包。例如,这段代码也可以正常工作:
🌐 Finally, self-referencing also works with scoped packages. For example, this
code will also work:
// package.json
{
"name": "@my/package",
"exports": "./index.js"
} 拷贝
// ./index.js
module.exports = 42; 拷贝
// ./other.js
console.log(require('@my/package')); 拷贝
$ node other.js
42 拷贝