编程 pnpm 11 升级:五个构建白名单设置合并成 allowBuilds,.npmrc 里除认证外的配置全失效

2026-11-04 21:03:17

pnpm 11 升级笔记:allowBuilds、配置搬家,以及会打断 CI 的默认值

官方材料两份,先放着:

  • 迁移指南:https://pnpm.io/zh/migration
  • 11.0 release 博客:https://pnpm.io/zh/blog/releases/11.0

运行环境门槛

pnpm 11 要求 Node.js 22+,18/19/20/21 都不再支持。pnpm 自身改成纯 ESM 分发,独立可执行文件要求 glibc 2.27+。CI 镜像和 Dockerfile 里的 Node 基础镜像需要先对齐,否则升级后装不起来不是配置问题,是运行时问题。

供应链默认值变严

这几个默认值不改也能跑,但 monorepo 的首次安装和锁文件更新行为会变:

  • minimumReleaseAge 默认 1440(分钟,即 1 天)。新发布的包至少要过一天才能被解析。急着上新版本时设 0 退出该限制。
  • minimumReleaseAgeStrict 默认 false。
  • blockExoticSubdeps 默认 true。
  • strictDepBuilds 默认 true。
  • optimisticRepeatInstall 默认 true。
  • verifyDepsBeforeRun 默认 install。

allowBuilds 取代五个旧设置

v11 移除了 onlyBuiltDependencies、onlyBuiltDependenciesFile、neverBuiltDependencies、ignoredBuiltDependencies、ignoreDepScripts,全部合成一个映射:包名匹配器 → true / false。

规则是:没写进 allowBuilds 的包,默认不允许执行构建脚本。当 strictDepBuilds 为默认的 true 时,这会按错误处理(ERR_PNPM_IGNORED_BUILDS);设成 false 则只警告。

安装时被忽略构建的依赖会被自动写进 pnpm-workspace.yaml,值是占位用的,需要你确认后再改。确认入口有两个:pnpm approve-builds,或者安装时加 --allow-build。

支持版本限定,例如:

allowBuilds:
"nx@21.6.4 || 21.6.5": true

键里带空格和 ||,YAML 里的引号写法建议按你所在 pnpm 版本实测验证一遍。

配置来源整体搬家

v11 不再读 package.json 里的 pnpm 字段。配置统一放 pnpm-workspace.yaml,全局配置放 config.yaml。

.npmrc 只保留认证与注册表相关项,例如:

registry=https://registry.npmjs.org/
//registry.npmjs.org/:_authToken=${NPM_TOKEN}

hoist-pattern、node-linker、save-exact 这类要搬到 pnpm-workspace.yaml,并改成驼峰键。子项目的 .npmrc 放到 packageConfigs["."] 下。

前后对照大致是这样:

# 升级前:.npmrc + package.json#pnpm
# .npmrc
hoist-pattern[]=*
node-linker=hoisted
save-exact=true
onlyBuiltDependencies[]=esbuild
onlyBuiltDependencies[]=sharp
ignoredBuiltDependencies[]=fsevents
# 升级后:pnpm-workspace.yaml
hoistPattern: "*"
nodeLinker: hoisted
saveExact: true
allowBuilds:
esbuild: true
sharp: true
fsevents: false

hoist-pattern 在 .npmrc 里是数组写法,搬到 YAML 后是字符串还是数组,按项目实际取值自行验证。

环境变量前缀改名

不再读 npm_config_*,改成 pnpm_config_*。要排查的地方比想象中多:CI 流水线变量、shell profile、Dockerfile 的 ENV、以及脚本里 cross-env npm_config_xxx=... 这种内联赋值。

其它破坏性改动

  • ignorePatchFailures 移除,补丁失败一律抛异常。
  • allowNonAppliedPatches 改名为 allowUnusedPatches。
  • auditConfig.ignoreCves 改名为 ignoreGhsas。值也要换:从 CVE-YYYY-NNNNN 手工改成 GHSA-xxxx-xxxx-xxxx,对应 ID 在 pnpm audit 输出的「更多信息」列里。
  • pnpm link 不带参数不再从全局 store 解析,要传相对或绝对路径。
  • pnpm install -g 不带参数不再支持,用 pnpm add -g。
  • pnpm server 移除,无替代。
  • useNodeVersion 改成根 package.json 的 devEngines.runtime。
  • 子包 package.json#pnpm 里的 executionEnv.nodeVersion 移除。

脚本名会遮蔽内置命令

如果 package.json 里定义了 clean、setup、deploy、rebuild,pnpm 现在跑的是你的脚本,不再是内置命令。要强制走内置命令,用 pnpm pm 。

存储与全局安装

store 换成 v11:每个包的 JSON 索引改成单个 SQLite 数据库,打包 manifest 和 hex 摘要,减少 syscall。

全局安装改成隔离模式:每次 pnpm add -g 有自己的目录、package.json、node_modules 和 lockfile,不再共享同一套依赖树。

发布不再走 npm CLI

publish、login、logout、view、deprecate、unpublish、dist-tag、version 都是原生实现。发布链路上如果有依赖 npm CLI 输出格式或行为的脚本,需要重新对一遍。

迁移步骤

机械改动交给 codemod:

pnpx codemod run pnpm-v10-to-v11

它会处理:package.json#pnpm → pnpm-workspace.yaml、拆分 .npmrc、合并构建设置、重命名各类键、升级 packageManager 版本。

装完 v11 后再跑一次,更新 shell 里的 bin 路径:

pnpm setup

codemod 覆盖不到的,是上面那些默认值和语义变化:minimumReleaseAge 的一天窗口、allowBuilds 白名单需要人工确认、ignoreGhsas 的 ID 换算、以及被脚本名遮住的内置命令。这些按项目实际情况逐条过。

复制全文 生成海报 pnpm 前端工程化 Node.js 迁移

推荐文章

程序员茄子在线接单