pnpm 11.7
pnpm 11.7 adds a frozenStore setting for installing against a read-only package store, a --batch flag for publishing a whole workspace in one request, scope-specific auth tokens, and full resolving installs delegated to pacquet. It also hardens lockfile alias handling, makes several install paths deterministic, and ships a number of publish and Windows fixes.
次要更改
New frozenStore setting
The new frozenStore setting (--frozen-store) lets pnpm install run against a package store that lives on a read-only filesystem — a Nix store, a read-only bind mount, or an OCI image layer.
When enabled, pnpm opens the store's SQLite index.db in immutable mode — bypassing the WAL/-shm sidecar files that otherwise can't be created on a read-only directory — and suppresses every code path that would write to the store. Pair it with --offline --frozen-lockfile against a fully-populated store:
pnpm install --frozen-store --offline --frozen-lockfile
The store must already contain everything the install needs, including the build output of any package whose lifecycle scripts are approved (or that has a patch). If a required build is missing under the global virtual store, the install fails up front with ERR_PNPM_FROZEN_STORE_NEEDS_BUILD instead of crashing mid-build on a read-only write — so seed those builds first.
frozenStore is incompatible with --force and with a configured pnpr server (both write into the store), and the side-effects cache is not written. The read-only store open requires Node.js >=22.15.0, >=23.11.0, or >=24.0.0; on older runtimes --frozen-store fails with a clear ERR_PNPM_FROZEN_STORE_UNSUPPORTED_NODE error.
pnpm publish --recursive --batch
The new opt-in --batch flag for pnpm publish --recursive sends all selected packages to the registry in a single PUT /-/pnpm/v1/publish request instead of one request per package.
The target registry has to implement the batch publish endpoint (pnpr does); registries that don't are reported with a clear ERR_PNPM_BATCH_PUBLISH_UNSUPPORTED error. The batch is processed all-or-nothing: if any package in the batch fails validation, none of the packages are published.
Scope-specific auth tokens
pnpm can now use different auth tokens for different package scopes, even when those scopes use the same registry URL. Previously auth was selected only by registry URL, so two scopes sharing a registry (such as GitHub Packages) had to share a token.
Configure a scope-specific token by adding the package scope after the registry URL in the auth key:
@org-a:registry=https://npm.pkg.github.com/
@org-b:registry=https://npm.pkg.github.com/
//npm.pkg.github.com/:@org-a:_authToken=ORG_A_TOKEN
//npm.pkg.github.com/:@org-b:_authToken=ORG_B_TOKEN
//npm.pkg.github.com/:_authToken=FALLBACK_TOKEN
When installing or publishing @org-a/*, pnpm uses ORG_A_TOKEN; for @org-b/*, it uses ORG_B_TOKEN. Packages without a matching scope fall back to the registry-wide token. pnpm login --registry=https://npm.pkg.github.com --scope=@org-a writes to the same scope-specific key. See Authentication Settings.
Full resolving installs delegated to pacquet
When pacquet (the Rust port of pnpm) is declared in configDependencies, pnpm now delegates dependency resolution to it too — not just materialization — provided the installed pacquet is new enough (>= 0.11.7).
Previously pacquet only ran in frozen-install mode: pnpm always resolved the graph itself and handed pacquet a finished lockfile to fetch / import / link. Now a non-frozen pnpm install (default isolated nodeLinker, plain install) is delegated to pacquet end-to-end in a single pass — it resolves the manifests, writes the lockfile, and materializes node_modules. Older pacquet releases keep the resolve-then-materialize split, and add / update / remove still resolve in pnpm. This remains an opt-in preview of the Rust install engine (#11723).
补丁更改
- Security: Reject path-traversal and reserved dependency aliases (such as
../../../escape,.bin,.pnpm, ornode_modules) that come from a lockfile rather than a freshly resolved manifest. A crafted lockfile alias could otherwise be joined directly under a hoistednode_modulesdirectory, letting package files be written outside the install root or overwrite pnpm-owned layout. The lockfile verification gate now runs an always-on, policy-independent check that rejects any invalid importer or snapshot alias before any fetch or filesystem work, for every node linker at once. - Prevent
pnpm patch-removefrom removing files outside the configured patches directory. - Fixed
pnpm publishignoringstrictSsl: falsewhen publishing to registries with self-signed certificates. The option is now forwarded tolibnpmpublish/npm-registry-fetch, the same way it is forpnpm install(#12012). - Fixed
Cannot destructure property 'manifest' of 'manifestsByPath[rootDir]'regression (introduced in 11.6.0) when runningpnpm add <pkg>outside a workspace on Windows (#12379). - Git dependencies that point to a subdirectory of a repository (
repo#commit&path:/sub/dir) keep theirpathin the lockfile again. Withoutpath, later installs from that lockfile silently unpacked the repository root instead of the subdirectory (#12304). - Made shared package child resolution deterministic when the same package is reached through multiple contexts (#12358).
- Fixed nondeterministic lockfile output that made
pnpm dedupe --checkfail intermittently in CI when a locked peer provider was pinned for a dependency with no children of its own. - Fix garbled summary line after submitting
pnpm update -iandpnpm audit --fix -i. The summary now lists only the selected package names (or vulnerability keys) instead of every selected choice's full table row. - User-defined
npm_config_*environment variables are now preserved during lifecycle script execution. Previously allnpm_-prefixed env vars were stripped, losing user-set variables likenpm_config_platform_arch(#12399). pnpm setupno longer prompts to approve build scripts for@pnpm/exewhen installing the standalone executable (#12377).- Sped up
pnpm installwith a frozen lockfile by running lockfile verification concurrently with fetching and linking instead of blocking the whole install on it. Dependency lifecycle scripts are still held back until verification succeeds, so no script runs on an unverified lockfile. - A
304 Not Modifiedanswer from the registry now renews the cached metadata file's mtime, so theminimumReleaseAgefreshness shortcut keeps serving resolutions from the cache instead of re-validating forever. - Fixed a Windows-only hang where a failed command could take 20–46 seconds to exit, caused by a slow
wmic/PowerShell descendant-process lookup that is now bounded by a short timeout. - Updated dependency ranges, notably
msgpackr1.11.8 → 2.0.4 (store index files remain byte-compatible in both directions),open^7.4.2 → ^11.0.0, and@zkochan/cmd-shimto v9.0.6.
