pnpm 11.0
pnpm 11 来了! 此版本加强了 v10 周期中引入的安全默认设置,放弃了 npm CLI 发布回退,转而采用原生实现,将每个包的 JSON 存储索引替换为单个 SQLite 数据库,并将全局安装隔离,使其不再相互干扰。
它还需要 Node.js 22 或更高版本——pnpm 本身现在是纯 ESM。
从 v10 升级? 请参阅 从 v10 迁移到 v11 指南。 大多数配置更改都是机械性的,可以通过 pnpm-v10-to-v11 代码转换来应用。
亮点
- 需要 Node.js 22+。 已停止支持 Node 18、19、20 和 21。 独立可执行文件需要 glibc 2.27 或更高版本。
- 供应链保护默认开启。
minimumReleaseAge默认为1440(1 天),blockExoticSubdeps默认为true。 allowBuilds取代了旧版构建依赖项设置。onlyBuiltDependencies、onlyBuiltDependenciesFile、neverBuiltDependencies、ignoredBuiltDependencies和ignoreDepScripts已移除。- 全局安装是隔离的,默认情况下使用全局虚拟存储。 每个
pnpm add -g都会获得自己的目录,其中包含自己的package.json、node_modules和 lockfile。 - 新的 SQLite 支持的存储索引(存储 v11),捆绑了清单和十六进制摘要,减少了系统调用,加快了安装速度。
- Native publish flow.
pnpm publish,login,logout,view,deprecate,unpublish,dist-tag, andversionno longer delegate to the npm CLI. .npmrc仅用于身份验证/注册源。 其他设置必须放在pnpm-workspace.yaml或新的全局config.yaml中。 环境变量使用pnpm_config_*前缀。
破坏性改动
需求
- 不支持 Node.js 18、19、20 和 21。
- pnpm 现在以纯 ESM 格式分发。
- 独立可执行文件需要 glibc 2.27+。
安全和构建默认值
多项默认值已翻转为更安全的值:
| 设置 | 新的默认值 |
|---|---|
minimumReleaseAge | 1440(1天) |
minimumReleaseAgeStrict | false |
blockExoticSubdeps | true |
strictDepBuilds | true |
optimisticRepeatInstall | true |
verifyDepsBeforeRun | install |
新发布的软件包至少要过 1 天才能被解析。 若要选择退出,在 pnpm-workspace.yaml 中设置 minimumReleaseAge: 0。
allowBuilds 取代了旧的构建设置
onlyBuiltDependencies、onlyBuiltDependenciesFile、neverBuiltDependencies、ignoredBuiltDependencies 和 ignoreDepScripts 都已被移除。 请改用 allowBuilds — 一个从包名称模式到布尔值的映射:
之前:
onlyBuiltDependencies:
- electron
onlyBuiltDependenciesFile: "allowed-builds.json"
neverBuiltDependencies:
- core-js
ignoredBuiltDependencies:
- esbuild
之后:
allowBuilds:
electron: true
core-js: false
esbuild: false
同时移除了:allowNonAppliedPatches(使用 allowUnusedPatches)和ignorePatchFailures(补丁失败现在会抛出异常)。
.npmrc 仅用于身份验证/注册源
pnpm 不再从 .npmrc 读取非身份验证设置。 配置分为两类:
- 注册源和认证设置 — INI 文件(
.npmrc, 全局rc文件,~/.config/pnpm/auth.ini)。 - pnpm 特定设置 — YAML 文件(
pnpm-workspace.yaml,新的全局~/.config/pnpm/config.yaml)。
其他相关变更:
-
pnpm 不再读取
npm_config_*环境变量。 请改用pnpm_config_*(例如pnpm_config_registry)。 -
pnpm 不再读取
package.json中的pnpm字段。 -
pnpm 不再读取 npm 的全局配置,位于
$PREFIX/etc/npmrc。 -
网络设置(
httpProxy、httpsProxy、noProxy、localAddress、strictSsl、gitShallowHosts)现在写入到config.yaml/pnpm-workspace.yaml中(仍然从.npmrc中读取以平滑迁移)。 -
pnpm-workspace.yaml文件中新增的registries设置替换了@scope:registry=行:registries:
default: https://registry.npmjs.org/
"@my-org": https://private.example.com/
"@internal": https://nexus.corp.com/ -
每个项目的
.npmrc文件被pnpm-workspace.yaml文件中的packageConfigs文件取代:packages:
- "packages/project-1"
- "packages/project-2"
packageConfigs:
"project-1":
saveExact: true
"project-2":
savePrefix: "~"
原生发布流程,不再使用 npm CLI 回退方案
以前通过传递给 npm CLI 实现的命令要么已经以原生方式重新实现,要么已经移除。
Reimplemented: publish, view (info, show, v), login (adduser), logout, deprecate, unpublish, dist-tag, version, search, star/unstar/stars, whoami, ping, docs/home.
已移除(现在抛出“未实现”):access、bugs、edit、issues、owner、prefix、profile、pkg、repo、set-script、team、token、xmas。
关于新的原生 pnpm publish 的一些说明:
- OTP 环境变量现在是
PNPM_CONFIG_OTP(以前是NPM_CONFIG_OTP)。 - 如果注册源要求提供 OTP 但未提供,pnpm 将以交互方式提示输入 OTP。
- 基于网页的身份验证会显示可扫描的二维码和网址。
pnpm audit 使用批量建议端点
注册源已停用旧版 /-/npm/v1/security/audits{,/quick} 端点。 pnpm audit 现在调用 /-/npm/v1/security/advisories/bulk,该命令不返回 CVE 标识符——因此,基于 CVE 的过滤已被基于 GHSA 的过滤所取代:
auditConfig.ignoreCves→auditConfig.ignoreGhsaspnpm audit --ignore <id>和--ignore-unfixable读取和写入 GHSA
要进行迁移,请将 ignoreCves 下的每个 CVE-YYYY-NNNNN 条目替换为匹配的 GHSA-xxxx-xxxx-xxxx(在 pnpm audit 的 More info 列中可见),并将其移动到 ignoreGhsas。
孤立的、全局虚拟存储的全局安装
pnpm add -g <pkg> 和 pnx 现在使用全局虚拟存储,并且每个安装都会在 {pnpmHomeDir}/global/v11/{hash}/ 获得自己的独立目录,其中包含自己的 package.json、node_modules/ 和锁文件。 这样可以防止全局包之间因对等依赖冲突、提升更改或版本错位而相互干扰。
pnpm remove -g <pkg>会删除包含该软件包的整个安装组。pnpm update -g [pkg]会将软件包重新安装到一个新的隔离目录中。pnpm list -g扫描隔离目录。pnpm install -g(不带参数)不再受支持——请使用pnpm add -g <pkg>。
全局安装的二进制文件现在位于 PNPM_HOME 的 bin 子目录中(而不是直接位于 PNPM_HOME 中),因此像 global/ 和 store/ 这样的内部目录不会污染 shell 自动补全。 升级后运行 pnpm setup 以更新 shell 配置。
pnpm link 也进行了收紧:只接受相对路径或绝对路径,移除了 --global(使用 pnpm add -g .),并且移除了不带参数的 pnpm link。
其他移除
-
pnpm server. -
useNodeVersion和executionEnv.nodeVersion— 使用devEngines.runtime/engines.runtime。 -
hooks.fetchers— 已被 pnpmfile 中的新fetchers字段取代。 -
managePackageManagerVersions、packageManagerStrict和packageManagerStrictVersion。 这些都继承了旧版packageManager字段的onFail行为;新的pmOnFail设置包含了它们:已移除 替换为 managePackageManagerVersions: truepmOnFail: download(默认)managePackageManagerVersions: falsepmOnFail: ignorepackageManagerStrict: falsepmOnFail: warnpackageManagerStrictVersion: truepmOnFail: errorCOREPACK_ENABLE_STRICT=0pmOnFail: warn
新命令
| 命令 | 它的作用 |
|---|---|
pnpm ci | 运行 pnpm clean,然后运行 pnpm install --frozen-lockfile。 别名:clean-install、ic、install-clean. |
pnpm clean | 从所有工作区项目中移除 node_modules。 --lockfile 也会删除 pnpm-lock.yaml。 |
pnpm sbom | 生成 CycloneDX 1.7 或 SPDX 2.3 JSON 格式的软件物料清单。 |
pnpm peers check | 报告锁文件中未满足/缺失的对等依赖。 |
pnpm runtime set | 安装运行时;弃用 pnpm env use。 |
pnpm docs / home | 打开软件包主页。 |
pnpm ping | 向注册源发送 Ping 请求。 |
pnpm with | 在单次调用中以特定(或当前)版本运行 pnpm,绕过 packageManager 的版本限制。 |
pnpm pack-app | 通过 Node.js SEA 将 CommonJS 条目打包成一个或多个目标平台的独立可执行文件。 |
Plus the natively reimplemented commands listed under "Native publish flow" above, and short aliases pn for pnpm and pnx for pnpx/pnpm dlx.
pnpm audit --fix=update
通过更新锁文件 中的软件包来修复易受伤害性,而不是添加覆盖。 为了实现更精细的控制,新增的 --interactive / -i 标志允许你选择要修复的警示:
pnpm audit --fix=update --interactive
pnpm audit --fix 还会将每个安全公告的最小补丁版本添加到 pnpm-workspace.yaml 中的 minimumReleaseAgeExclude,这样就可以在不等待 minimumReleaseAge 的情况下安装安全修复程序。
ESM pnpmfiles
现在可以使用 .mjs 扩展名以 ESM 格式编写 pnpmfiles。 当 .pnpmfile.mjs 存在时,它的优先级高于 .pnpmfile.cjs,并且只会加载其中一个。
存储 v11
该存储的重建围绕两个理念展开:减少读取,减少系统调用。
- 现在,软件包索引是一个位于
$STORE/index.db的单个 SQLite 数据库(具有 MessagePack 值,WAL 模式用于并发访问),而不是位于$STORE/index/下的数百万个 JSON 文件。 新索引中缺失的软件包会根据需要重新获取。 - 捆绑清单(名称、版本、bin、引擎、脚本等) 直接存储在软件包索引中,无需在解析和安装过程中从 CAS 读取
package.json。 - 索引条目存储十六进制摘要,而不是完整的完整性字符串(
<algo>-<digest>),并且哈希算法每个文件记录一次,而不是每个条目记录一次。 这样可以避免每次 CAS 路径查找时进行 base64 → hex 转换。 - 启用全局虚拟存储后,不允许构建的软件包(并且不间接依赖于允许构建的软件包)将获得不包含引擎名称(平台、架构、Node.js 主版本号)的哈希值。 现在约 95% 的 GVS 包无需重新导入即可在 Node.js 升级和架构变更后继续保留。
性能
许多小胜利增加了一个明显更快的安装:
undici取代了node-fetch用于所有 HTTP 请求,具有 Happy Eyeballs(双栈)、更好的 keep-alive 和优化的全局调度器。- 已知大小的 Tarball 下载会预先分配内存,以避免重复复制带来的开销。
- 元数据缓存现在采用 NDJSON 格式,并带有
If-Modified-Since以进行条件获取。 minimumReleaseAge检查使用 简化的元数据 端点来获取更少的信息。- CAS 文件直接写入其内容寻址路径,而不是通过临时文件 + 重命名 — 每次冷安装可节省约 30k 次重命名系统调用。
- 导入到
node_modules时,暂存目录消失了。 - CAS 中的热路径字符串操作得到了加强,
gunzipSync运行时使用更大的块大小,以减少 tarball 解压缩期间的缓冲区分配。 - 在 GVS 热重装过程中,如果没有添加任何软件包,则会跳过冗余的内部链接。
更精简的运行时安装
通过 node@runtime:<version>(包括 pnpm env use 和 pnpm runtime set node)安装 Node.js 运行时不再从 Node.js 归档中提取捆绑的 npm、npx 和 corepack。 这大约减少了一半数量的pnpm需要哈希、写入CAS和链接的文件。 如果仍然需要 npm,请将其作为单独的软件包安装。
其他重要改动
-
更清晰的脚本输出。
pnpm现在打印$ command(到 stderr,因此 stdout 保持管道友好),而不是> pkg@version stage path\n> command。 只有在不同目录下运行时才会显示项目名称和路径。 -
安装过程中,对等依赖关系问题不再以树状结构呈现——pnpm 建议运行
pnpm peers check来查看它们。 -
生命周期脚本不再从 pnpm 配置中获取
npm_config_*环境变量;仅设置众所周知的npm_*环境变量,与 Yarn 一致。 -
当启用
init-package-manager时,pnpm init会写入devEngines.packageManager而不是packageManager,并且默认的type现在是"module"。 -
devEngines.packageManager现在支持版本范围;解析后的版本存储在pnpm-lock.yaml中,如果仍然满足范围,则会被重用。 -
dedupePeers是一个新设置,它使用仅包含版本信息的后缀 (name@version) 而不是完整的依赖路径,从而消除具有许多递归对等项的项目的嵌套后缀,例如(foo@1.0.0(bar@2.0.0))。 -
pnpm approve-builds现在接受用于非交互式使用的位置参数;在名称前加上!即可拒绝。 -
隐藏脚本 — 以
.开头的脚本只能从其他脚本调用,并且不会显示在pnpm run中。 -
-F是--filter的新简短别名。 -
pnpm add短标志 —-d现在是--save-dev,-p是--save-prod,-o是--save-optional,-e是--save-exact(仅在pnpm add内部)。 -
virtualStoreOnly在不创建导入器符号链接、提升、bin 链接或运行生命周期脚本下填充虚拟存储。 在 Nix 构建中预先填充存储很有用。pnpm fetch现在内部使用此功能。 -
pnpm-workspace.yaml中的nodeDownloadMirrors替换了.npmrc中的node-mirror:<channel>设置:nodeDownloadMirrors:
release: https://my-mirror.example.com/download/release/ -
配置依赖项 现在已安装到
{storeDir}/links/中,并且符号链接到node_modules/.pnpm-config/,因此它们可以在使用同一存储的项目之间共享。 已解析的版本和完整性哈希值已从pnpm-workspace.yaml移至pnpm-lock.yaml中的单独文档;旧的内联哈希项目会自动迁移。
升级
有关代码转换和后续操作的完整指南,请参阅 从 v10 迁移到 v11。 简短版本:
- 升级前,请将 CI 和开发环境升级到 Node.js 22+ 版本。
- 将 pnpm 设置从
.npmrc移到pnpm-workspace.yaml(或全局的~/.config/pnpm/config.yaml)。 - 将
onlyBuiltDependencies及其相关功能迁移到allowBuilds。 - 将
auditConfig.ignoreCves迁移到auditConfig.ignoreGhsas。 - 安装 v11 后,运行
pnpm setup来更新你的 shell,以便将新的bin子目录添加到PATH中。
完整的更改列表在 更改日志。 如果你依赖的某些功能缺失或损坏,请在 github.com/pnpm/pnpm/issues 上提交问题。
