跳到主内容

pnpm 11.0

· 一分钟阅读
Zoltan Kochan
pnpm 的首席维护者

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 取代了旧版构建依赖项设置。 onlyBuiltDependenciesonlyBuiltDependenciesFileneverBuiltDependenciesignoredBuiltDependenciesignoreDepScripts 已移除。
  • 全局安装是隔离的,默认情况下使用全局虚拟存储。 每个 pnpm add -g 都会获得自己的目录,其中包含自己的 package.jsonnode_modules 和 lockfile。
  • 新的 SQLite 支持的存储索引(存储 v11),捆绑了清单和十六进制摘要,减少了系统调用,加快了安装速度。
  • Native publish flow. pnpm publish, login, logout, view, deprecate, unpublish, dist-tag, and version no 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+。

安全和构建默认值

多项默认值已翻转为更安全的值:

设置新的默认值
minimumReleaseAge1440(1天)
minimumReleaseAgeStrictfalse
blockExoticSubdepstrue
strictDepBuildstrue
optimisticRepeatInstalltrue
verifyDepsBeforeRuninstall

新发布的软件包至少要过 1 天才能被解析。 若要选择退出,在 pnpm-workspace.yaml 中设置 minimumReleaseAge: 0

allowBuilds 取代了旧的构建设置

onlyBuiltDependenciesonlyBuiltDependenciesFileneverBuiltDependenciesignoredBuiltDependenciesignoreDepScripts 都已被移除。 请改用 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

  • 网络设置(httpProxyhttpsProxynoProxylocalAddressstrictSslgitShallowHosts)现在写入到 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.

已移除(现在抛出“未实现”):accessbugseditissuesownerprefixprofilepkgreposet-scriptteamtokenxmas

关于新的原生 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.ignoreCvesauditConfig.ignoreGhsas
  • pnpm audit --ignore <id>--ignore-unfixable 读取和写入 GHSA

要进行迁移,请将 ignoreCves 下的每个 CVE-YYYY-NNNNN 条目替换为匹配的 GHSA-xxxx-xxxx-xxxx(在 pnpm auditMore info 列中可见),并将其移动到 ignoreGhsas

孤立的、全局虚拟存储的全局安装

pnpm add -g <pkg>pnx 现在使用全局虚拟存储,并且每个安装都会在 {pnpmHomeDir}/global/v11/{hash}/ 获得自己的独立目录,其中包含自己的 package.jsonnode_modules/ 和锁文件。 这样可以防止全局包之间因对等依赖冲突、提升更改或版本错位而相互干扰。

  • pnpm remove -g <pkg> 会删除包含该软件包的整个安装组。
  • pnpm update -g [pkg] 会将软件包重新安装到一个新的隔离目录中。
  • pnpm list -g 扫描隔离目录。
  • pnpm install -g(不带参数)不再受支持——请使用 pnpm add -g <pkg>

全局安装的二进制文件现在位于 PNPM_HOMEbin 子目录中(而不是直接位于 PNPM_HOME 中),因此像 global/store/ 这样的内部目录不会污染 shell 自动补全。 升级后运行 pnpm setup 以更新 shell 配置。

pnpm link 也进行了收紧:只接受相对路径或绝对路径,移除了 --global(使用 pnpm add -g .),并且移除了不带参数的 pnpm link

其他移除

  • pnpm server.

  • useNodeVersionexecutionEnv.nodeVersion — 使用 devEngines.runtime / engines.runtime

  • hooks.fetchers — 已被 pnpmfile 中的新 fetchers 字段取代。

  • managePackageManagerVersionspackageManagerStrictpackageManagerStrictVersion。 这些都继承了旧版 packageManager 字段的 onFail 行为;新的 pmOnFail 设置包含了它们:

    已移除替换为
    managePackageManagerVersions: truepmOnFail: download(默认)
    managePackageManagerVersions: falsepmOnFail: ignore
    packageManagerStrict: falsepmOnFail: warn
    packageManagerStrictVersion: truepmOnFail: error
    COREPACK_ENABLE_STRICT=0pmOnFail: warn

新命令

命令它的作用
pnpm ci运行 pnpm clean,然后运行 pnpm install --frozen-lockfile。 别名:clean-installicinstall-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 usepnpm runtime set node)安装 Node.js 运行时不再从 Node.js 归档中提取捆绑的 npmnpxcorepack。 这大约减少了一半数量的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 上提交问题。