包入口点


【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 定义清晰。例如,一个之前导出 mainlibfeaturepackage.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
  }
}