Перейти до основного змісту

pnpm 11.7

· 6 хв читання
Золтан Кочан
Головний розробник pnpm

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, or node_modules) that come from a lockfile rather than a freshly resolved manifest. A crafted lockfile alias could otherwise be joined directly under a hoisted node_modules directory, 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-remove from removing files outside the configured patches directory.
  • Fixed pnpm publish ignoring strictSsl: false when publishing to registries with self-signed certificates. The option is now forwarded to libnpmpublish / npm-registry-fetch, the same way it is for pnpm install (#12012).
  • Fixed Cannot destructure property 'manifest' of 'manifestsByPath[rootDir]' regression (introduced in 11.6.0) when running pnpm add <pkg> outside a workspace on Windows (#12379).
  • Git dependencies that point to a subdirectory of a repository (repo#commit&path:/sub/dir) keep their path in the lockfile again. Without path, 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 --check fail 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 -i and pnpm 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 all npm_-prefixed env vars were stripped, losing user-set variables like npm_config_platform_arch (#12399).
  • pnpm setup no longer prompts to approve build scripts for @pnpm/exe when installing the standalone executable (#12377).
  • Sped up pnpm install with 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 Modified answer from the registry now renews the cached metadata file's mtime, so the minimumReleaseAge freshness 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 msgpackr 1.11.8 → 2.0.4 (store index files remain byte-compatible in both directions), open ^7.4.2 → ^11.0.0, and @zkochan/cmd-shim to v9.0.6.