package.json
包的清单文件。它包含了包的所有元数据,包括依赖、标题、作者等信息。这是所有主要的 Node.js 包管理器(包括 pnpm)都保留的标准。
🌐 The manifest file of a package. It contains all the package's metadata, including dependencies, title, author, et cetera. This is a standard preserved across all major Node.js package managers, including pnpm.
除了传统的 package.json 格式外,pnpm 还支持 package.json5(通过 json5)和 package.yaml(通过 js-yaml)。
🌐 In addition to the traditional package.json format, pnpm also supports package.json5 (via json5) and package.yaml (via js-yaml).
engines
你可以指定你的软件运行的 Node 和 pnpm 版本:
🌐 You can specify the version of Node and pnpm that your software works on:
{
"engines": {
"node": ">=10",
"pnpm": ">=3"
}
}
在本地开发过程中,如果 pnpm 的版本与 engines 字段中指定的版本不匹配,它将始终报错。
🌐 During local development, pnpm will always fail with an error message
if its version does not match the one specified in the engines field.
除非用户已设置 engineStrict 配置标志(参见 settings),否则此字段仅为参考,并且仅在你的包作为依赖安装时才会产生警告。
🌐 Unless the user has set the engineStrict config flag (see settings), this
field is advisory only and will only produce warnings when your package is
installed as a dependency.
engines.runtime
新增于:v10.21.0
🌐 Added in: v10.21.0
指定依赖所需的 Node.js 运行时。声明后,pnpm 会自动安装指定的 Node.js 版本。
🌐 Specifies the Node.js runtime required by a dependency. When declared, pnpm will automatically install the specified Node.js version.
{
"engines": {
"runtime": {
"name": "node",
"version": "^24.11.0",
"onFail": "download"
}
}
}
当软件包声明运行时:
🌐 When a package declares a runtime:
- 对于命令行应用:pnpm 将 CLI 绑定到所需的 Node.js 版本,确保无论全局安装的 Node.js 实例如何,都能使用正确的运行时。
- 对于带有
postinstall脚本的包:脚本将使用指定的 Node.js 版本执行。
这对于需要特定 Node.js 版本才能正常运行的依赖尤其有用。
🌐 This is particularly useful for dependencies that require specific Node.js versions to function correctly.
devEngines.runtime
添加于:v10.14
🌐 Added in: v10.14
允许指定项目使用的一个或多个 JavaScript 运行时引擎。支持的运行时包括 Node.js、Deno 和 Bun。
🌐 Allows to specify one or more JavaScript runtime engines used by the project. Supported runtimes are Node.js, Deno, and Bun.
例如,下面是如何将 node@^24.4.0 添加到你的依赖中:
🌐 For instance, here is how to add node@^24.4.0 to your dependencies:
{
"devEngines": {
"runtime": {
"name": "node",
"version": "^24.4.0",
"onFail": "download"
}
}
}
你也可以向同一个 package.json 添加多个运行时:
🌐 You can also add multiple runtimes to the same package.json:
{
"devEngines": {
"runtime": [
{
"name": "node",
"version": "^24.4.0",
"onFail": "download"
},
{
"name": "deno",
"version": "^2.4.3",
"onFail": "download"
}
]
}
}
工作原理:
🌐 How it works:
pnpm install将你指定的范围解析为最新匹配的运行时版本。- 确切的版本(以及校验和)保存在锁文件中。
- 脚本使用本地运行时,确保跨环境的一致性。
dependenciesMeta
用于 dependencies、optionalDependencies 和 devDependencies 中声明的依赖的附加元信息。
🌐 Additional meta information used for dependencies declared inside dependencies, optionalDependencies, and devDependencies.
dependenciesMeta.*.injected
如果将此设置为 true,对于本地工作区包的依赖,该包将通过在虚拟存储 (node_modules/.pnpm) 中创建硬链接副本来安装。
🌐 If this is set to true for a dependency that is a local workspace package, that package will be installed by creating a hard linked copy in the virtual store (node_modules/.pnpm).
如果将其设置为 false 或未设置,则依赖将通过创建一个指向工作区中包源目录的 node_modules 符号链接来安装。这是默认设置,因为它更快,并且可以确保对依赖的任何修改将立即对其使用者可见。
🌐 If this is set to false or not set, then the dependency will instead be installed by creating a node_modules symlink that points to the package's source directory in the workspace. This is the default, as it is faster and ensures that any modifications to the dependency will be immediately visible to its consumers.
例如,假设以下 package.json 是一个本地工作区包:
🌐 For example, suppose the following package.json is a local workspace package:
{
"name": "card",
"dependencies": {
"button": "workspace:1.0.0"
}
}
button 依赖通常通过在 card 的 node_modules 目录中创建一个指向 button 开发目录的符号链接来安装。
🌐 The button dependency will normally be installed by creating a symlink in the node_modules directory of card, pointing to the development directory for button.
但是如果 button 在它的 peerDependencies 中指定了 react 会怎样?如果 monorepo 中的所有项目都使用相同版本的 react,那么就没有问题。但如果 button 被 card(使用 react@16)和 form(使用 react@17)所需要呢?通常你必须选择一个单一版本的 react,并使用 button 的 devDependencies 来指定它。符号链接并不能为 react 的 peer 依赖提供不同消费者(如 card 和 form)使用不同版本的方式。
🌐 But what if button specifies react in its peerDependencies? If all projects in the monorepo use the same version of react, then there is no problem. But what if button is required by card that uses react@16 and form that uses react@17? Normally you'd have to choose a single version of react and specify it using devDependencies of button. Symlinking does not provide a way for the react peer dependency to be satisfied differently by different consumers such as card and form.
injected 字段通过在虚拟存储中安装 button 的硬链接副本来解决此问题。为此,card 的 package.json 可以按如下方式配置:
🌐 The injected field solves this problem by installing a hard linked copies of button in the virtual store. To accomplish this, the package.json of card could be configured as follows:
{
"name": "card",
"dependencies": {
"button": "workspace:1.0.0",
"react": "16"
},
"dependenciesMeta": {
"button": {
"injected": true
}
}
}
而 form 的 package.json 可以配置如下:
🌐 Whereas the package.json of form could be configured as follows:
{
"name": "form",
"dependencies": {
"button": "workspace:1.0.0",
"react": "17"
},
"dependenciesMeta": {
"button": {
"injected": true
}
}
}
通过这些更改,我们说 button 是 card 和 form 的“注入依赖”。当 button 导入 react 时,它将在 card 的上下文中解析为 react@16,但在 form 的上下文中解析为 react@17。
🌐 With these changes, we say that button is an "injected dependency" of card and form. When button imports react, it will resolve to react@16 in the context of card, but resolve to react@17 in the context of form.
由于注入的依赖会生成其工作区源目录的副本,因此每当代码被修改时,这些副本必须以某种方式更新;否则,消费者将无法反映新的状态。在使用类似 pnpm --recursive run build 的命令构建多个项目时,这种更新必须在每个注入包重建之后,但在其消费者重建之前进行。对于简单的用例,可以通过再次调用 pnpm install 来实现,可能会使用类似 "prepare": "pnpm run build" 的 package.json 生命周期脚本来重建该项目。第三方工具如 pnpm-sync 和 pnpm-sync-dependencies-meta-injected 提供了更健壮和高效的解决方案来更新注入的依赖,同时也支持监视模式。
🌐 Because injected dependencies produce copies of their workspace source directory, these copies must be updated somehow whenever the code is modified; otherwise, the new state will not be reflected for consumers. When building multiple projects with a command such as pnpm --recursive run build, this update must occur after each injected package is rebuilt but before its consumers are rebuilt. For simple use cases, it can be accomplished by invoking pnpm install again, perhaps using a package.json lifecycle script such as "prepare": "pnpm run build" to rebuild that one project. Third party tools such as pnpm-sync and pnpm-sync-dependencies-meta-injected provide a more robust and efficient solution for updating injected dependencies, as well as watch mode support.
peerDependenciesMeta
此字段列出了与 peerDependencies 字段中列出的依赖相关的一些额外信息。
🌐 This field lists some extra information related to the dependencies listed in
the peerDependencies field.
peerDependenciesMeta.*.optional
如果将此设置为 true,所选的对等依赖将被包管理器标记为可选。因此,使用者省略它将不再被报告为错误。
🌐 If this is set to true, the selected peer dependency will be marked as optional by the package manager. Therefore, the consumer omitting it will no longer be reported as an error.
例如:
🌐 For example:
{
"peerDependencies": {
"foo": "1"
},
"peerDependenciesMeta": {
"foo": {
"optional": true
},
"bar": {
"optional": true
}
}
}
请注意,即使在 peerDependencies 中未指定 bar,它也被标记为可选。因此,pnpm 将假定 bar 的任何版本都是可以的。然而,foo 是可选的,但仅针对所需的版本规范。
🌐 Note that even though bar was not specified in peerDependencies, it is
marked as optional. pnpm will therefore assume that any version of bar is fine.
However, foo is optional, but only to the required version specification.
publishConfig
在打包之前,可以覆盖清单中的某些字段。以下字段可以被覆盖:
🌐 It is possible to override some fields in the manifest before the package is packed. The following fields may be overridden:
binmainexportstypes或typingsmodulebrowseresnextes2015unpkgumd:maintypesVersions- cpu
- os
engines(在 v10.22.0 中添加)
要重写字段,请将该字段的发布版本添加到 publishConfig。
🌐 To override a field, add the publish version of the field to publishConfig.
例如,以下的 package.json:
🌐 For instance, the following package.json:
{
"name": "foo",
"version": "1.0.0",
"main": "src/index.ts",
"publishConfig": {
"main": "lib/index.js",
"typings": "lib/index.d.ts"
}
}
将发布为:
🌐 Will be published as:
{
"name": "foo",
"version": "1.0.0",
"main": "lib/index.js",
"typings": "lib/index.d.ts"
}
publishConfig.executableFiles
默认情况下,为了可移植性,除了在 bin 字段中列出的文件外,生成的包归档中的其他文件不会被标记为可执行。executableFiles 字段允许你声明额外的文件,即使它们不能通过 bin 字段直接访问,也必须设置可执行标志 (+x)。
🌐 By default, for portability reasons, no files except those listed in the bin field will be marked as executable in the resulting package archive. The executableFiles field lets you declare additional files that must have the executable flag (+x) set even if they aren't directly accessible through the bin field.
{
"publishConfig": {
"executableFiles": [
"./dist/shim.js"
]
}
}
publishConfig.directory
你也可以使用字段 publishConfig.directory 来自定义相对于当前 package.json 的发布子目录。
🌐 You also can use the field publishConfig.directory to customize the published subdirectory relative to the current package.json.
预计在指定目录中会有当前包的修改版本(通常使用第三方构建工具)。
🌐 It is expected to have a modified version of the current package in the specified directory (usually using third party build tools).
在此示例中,
"dist"文件夹必须包含一个package.json
{
"name": "foo",
"version": "1.0.0",
"publishConfig": {
"directory": "dist"
}
}
publishConfig.linkDirectory
- 默认:真
- 类型:布尔
当设置为 true 时,项目将在本地开发期间从 publishConfig.directory 位置创建符号链接。
🌐 When set to true, the project will be symlinked from the publishConfig.directory location during local development.
例如:
🌐 For example:
{
"name": "foo",
"version": "1.0.0",
"publishConfig": {
"directory": "dist",
"linkDirectory": true
}
}