pnpm 11.21-11.22
pnpm 11.21 和 11.22 版本对 pnpm install 进行了多项改进:针对大多数日常变更,改为原地更新锁文件而非重新解析整个依赖图;停止记录会导致 CI 环境安装失败的 SSH URL;实现全局安装的原子切换,并支持在全局交互式更新中选择整个安装组;新增 pnpm cache path 命令;同时移除了通过 pnpm-workspace.yaml 重新定位 pnpm 机器级状态的功能。
次要更改
项目无法再迁移机器级状态
你克隆的仓库不应决定 pnpm 存储凭据的位置、其自身的安装位置,也不应决定其下载后续版本所使用的注册源。 自 v11.22.0 版本起,项目 pnpm-workspace.yaml 中的 bin、configDir、dir、globalBinDir、globalDir、npmrcAuthFile、pnpmHomeDir、stateDir、userconfig 和 workspaceDir 配置项将被忽略,并会发出警告;cacheDir 和 storeDir 不受影响 (#13629)。
为了确保这一规则清晰可见,我们采取了以下两项措施:pnpm config set 现在会拒绝将此类配置写入 pnpm-workspace.yaml(并抛出 ERR_PNPM_CONFIG_SET_NOT_A_PROJECT_SETTING 错误,指明该配置项的正确归属位置);此外,通过项目清单合并机制使用 --config. 形式的标志也不再起作用——实际上,这种方式原本就不受支持用于设置这些目录。
关于在 sudo 下运行全局命令的警告
pnpm 将全局包和配置存储在调用该命令的用户的家目录中,因此如果使用 sudo 运行 pnpm setup、pnpm self-update 或 pnpm add --global,操作将静默地作用于 root 用户的家目录,而不是你自己的家目录。 从 v11.21.0 版本开始,以 root 身份运行这些命令时会输出警告;而在 pnpm v12 中,这些命令会失败并报错 ERR_PNPM_SUDO_NOT_SUPPORTED。 诸如 pnpm bin --global 之类的只读全局命令不受影响。
交互式全局更新选择安装组
pnpm update --global --interactive 现在将每个独立安装组作为一个可选项进行展示。 共享全局安装的软件包会相互关联,因此它们会作为一个整体进行更新;更新范围仅限于你选定的那些组。
pnpm cache path
新的 pnpm cache path 命令会输出 pnpm 用于元数据缓存的目录。 CI 配置可以持久化保存该目录——其中包括锁文件的验证日志;这使得作业能够跳过针对已配置的供应链策略对未变更的锁文件进行的重新检查。 pnpm store prune 也不再删除那个日志文件。 See Continuous Integration for the recipe.
Pruning stale release-age exclusions
The new minimumReleaseAgeExcludePrune setting makes pnpm add, pnpm update, and pnpm remove drop minimumReleaseAgeExclude entries that the freshly written lockfile no longer resolves, so the exclusion list shrinks back as the pinned versions age out. Name patterns (@myorg/*) are always kept.
In the same spirit, cleanupUnusedCatalogs is renamed to catalogPrune, so catalog pruning and release-age exclude pruning use one vocabulary. The old spelling keeps working; when both are set, catalogPrune wins.
Faster runtime resolution
Resolving a Node.js runtime version (devEngines.runtime / runtime: specifiers) is much faster: per-version release metadata is cached after its signature is verified, and an exact stable version such as runtime:22.23.2 no longer downloads the Node.js release index. A pinned runtime whose metadata was fetched once resolves without any network access, which removes the noticeable delay on the first node invocation in a project pinning an already-downloaded runtime (#13899).
补丁更改
Most everyday changes no longer re-resolve the dependency graph
Previously, many routine edits forced pnpm install to re-resolve the whole dependency graph, even when the lockfile already contained everything needed. Across these two releases, the lockfile is now updated in place — no registry round-trips, no churn beyond the entries that actually changed — for:
- removing a dependency, including pruning what it alone made reachable and dropping a catalog entry that lost its last referent;
pnpm addof a version the lockfile already holds — promoting a transitive dependency to a direct one, or adding to a second workspace package what a first one already uses (#13696);- moving a dependency between
dependencies,devDependencies, andoptionalDependencies; - adding a new workspace package whose dependencies are all locked for a sibling;
- widening or changing a range that an already-locked version satisfies — now picking the highest satisfying locked version, matching what a full resolution records (#13778);
- changing a catalog entry to a different exact version, and combinations of catalog and
pnpm.overridesedits with other changes (#13799); - changing
pnpm.overridesto a satisfiable range, and parent-scoped overrides ("parent>child": "2.0.0") (#13795); - adding, editing, or removing
patchedDependenciesentries andignoredOptionalDependenciespatterns; - flipping
autoInstallPeers,dedupePeers,peersSuffixMaxLength,excludeLinksFromLockfile, orinjectWorkspacePackageswhen the lockfile proves the setting cannot affect the resolution.
Projects with a pnpmfile use these fast paths too, as long as the recorded pnpmfileChecksum proves the pnpmfile is unchanged. Every case that could change the resolution — a peer reached through the edited package, a dist tag, an exotic specifier — still falls back to a full resolution.
Git dependencies work on CI runners without SSH keys
Since v11.21.0, the Git resolver no longer records an SSH URL unless the specifier explicitly asks for one (git+ssh:// or git@host:...). A shorthand like github:owner/repo resolves and records over HTTPS, so a lockfile written on a machine with SSH keys no longer fails on a CI runner with Permission denied (publickey) (#13276). The repository visibility probe also retries throttled responses, and a repository that cannot be confirmed public keeps a regular git resolution so installs can use ambient credentials.
v11.22.0 improves what you see when Git resolution or fetching still fails: errors carry the ERR_PNPM_GIT_RESOLVE_FAILED / ERR_PNPM_GIT_FETCH_FAILED codes, name the dependency instead of printing a bare git invocation, redact credentials embedded in repository URLs, and explain how to route HTTPS URLs over SSH on machines that need it (#13743). An SSH URL recorded by a pre-11.21 lockfile can be re-recorded over HTTPS with pnpm update <package>.
Global installs switch over atomically
The command shims in the global bin directory now point at a stable per-package link rather than at the directory a particular install produced, so pnpm add -g and pnpm update -g activate a new version by moving one link instead of rewriting every shim. A command can no longer be missing from PATH while an install is in progress, and a failed install leaves the previous version in place.
The automatic packageManager switch works behind feed proxies
The automatic version switch works again on registries whose tarball URLs point at a different host than the registry itself (load-balanced feed proxies, Artifactory-style mirrors) (#13619), and registries that strip npm's signature metadata no longer break it or pnpm self-update: when the configured registry cannot provide a verifiable signature, pnpm fetches one from registry.npmjs.org and verifies it against the same embedded npm keys over the installed integrity (#13147).
Other notable fixes
resolutionMode: lowest-directandtime-basedwork again whileminimumReleaseAgeis in effect — including its built-in default, which previously forced the highest version silently (#13752).pnpm updatewithout saving no longer records a version the manifest's range excludes, which the nextpnpm install --frozen-lockfilerejected (#12764).pnpm deployinjects workspace dependencies again, so the deploy directory is self-contained instead of symlinking back into the source workspace (#13754).pnpm add <pkg>@<version>under a non-manualcatalogModenow moves the catalog entry's resolution instead of silently doing nothing, andcatalogMode: strictaccepts a version the catalog's range covers (#13715).syncInjectedDepsAfterScriptssurvives FIFOs and file/directory swaps in workspace packages, removes bin links a build step stopped declaring, and identifies files by device as well as inode (#13550).pnpm root -gandpnpm bin -gprint warnings to stderr, keeping stdout a clean machine-readable path (#13672).- Lockfile verification honors offline mode, using cached registry metadata instead of reaching the registry.
pnpm audit --fix不再为那些发布时间已足够长、从而自然满足“最低发布时长”限制的已修复版本添加minimumReleaseAgeExclude条目 (#11563)。- 针对 Git 依赖简写、
minimumReleaseAgedist-tag 回退机制、暂缓更新警告、全局虚拟存储下的link:依赖以及仅涉及移除包的安装操作,均进行了正确性修复——完整列表请参阅发布说明。
