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

pnpm 11.2

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

pnpm 11.2 ships an experimental opt-in into pacquet (the Rust port of pnpm) as the install backend, expands config dependencies to install one level of optionalDependencies (so the esbuild/swc platform-binary pattern works for config deps too), wires up the long-documented pnpm login --scope flag, and surfaces runtime entries (Node.js, Deno, Bun) in pnpm outdated and pnpm update --interactive.

Незначні зміни

Experimental: pacquet as the install backend

Adding @pnpm/pacquet (the Rust port of pnpm) to configDependencies in pnpm-workspace.yaml now delegates the materialization phase of pnpm install to the pacquet binary. pnpm still owns dependency resolution; pacquet only fetches and imports from the freshly-written lockfile. This is an opt-in preview of the Rust install engine — see #11723.

To configure pacquet in a project, run:

pnpm add @pnpm/pacquet --config

You'll see changes in pnpm-workspace.yaml and pnpm-lock.yaml that should be committed. If you experience any issues with pacquet, please let us know in the GitHub issue you create.

optionalDependencies for config dependencies

Config dependencies now resolve and install one level of optionalDependencies declared by the config dependency, with os / cpu / libc platform filtering applied at install time. This unlocks the esbuild/swc-style pattern where a package ships platform-specific binaries via optionalDependencies — a config dependency can now do the same and have the matching binary symlinked next to it in the global virtual store, so require('pkg-platform-arch') from inside the config dependency resolves correctly.

The env lockfile records all platform variants regardless of host platform, so it remains portable across machines. Each entry in a config dependency's optionalDependencies must declare an exact version — ranges and tags are rejected to keep installs reproducible.

pnpm login --scope

The long-documented pnpm login --scope <scope> flag is now implemented. The scope is normalized (a leading @ is added if missing; blank values are ignored) and an @<scope>:registry=<registry> mapping is written to the pnpm auth file alongside the auth token. Subsequent installs of @<scope>/* packages then route to the chosen registry. Previously the documented flag errored with Unknown option: 'scope'. See #11716.

Runtimes in outdated and update --interactive

pnpm outdated and pnpm update --interactive now report Node.js, Deno, and Bun runtimes installed as project dependencies (runtime: specifiers). Previously these were silently skipped.

Зміни в патчах

  • Fixed cafile=<relative-path> in .npmrc being read from the wrong directory when pnpm is invoked from a different cwd (e.g. pnpm --dir <project> install from a CI wrapper or monorepo script). The path is now resolved against the directory of the .npmrc that declared it, not process.cwd(). Before this fix, the install proceeded without the configured CA and the user only saw TLS errors against a private registry with no log line tying back to the wrongly resolved path #11624.
  • Fixed config.registry getting a trailing slash appended when registry is set in .npmrc and no registries.default is provided by pnpm-workspace.yaml.
  • Fixed global add/update to handle minimumReleaseAge policy violations instead of surfacing an internal resolver guardrail error.
  • Fixed two crashes with injectWorkspacePackages: true when the lockfile has been pruned (e.g. by turbo prune --docker): a Cannot use 'in' operator to search for 'directory' in undefined from peer-dependency-variant injected snapshots whose base packages: entry had been dropped, and an ERR_PNPM_ENOENT on node_modules/.bin/<tool> after prepare / postinstall re-imported each injected workspace package.
  • Fixed pnpm login and pnpm logout ignoring registries.default from pnpm-workspace.yaml #10099.
  • Fixed the minimumReleaseAge (publishedBy) maturity shortcut to be inclusive at the cutoff. Previously, abbreviated metadata whose modified field equalled the cutoff fell off the fast path and triggered a full-metadata re-fetch (or a MISSING_TIME error when full metadata wasn't permitted).
  • Honor publishConfig.access when publishing packages.

11.2.1

  • Mark optional subdependency snapshots of config dependencies with optional: true in the env lockfile, matching how optional dependencies are recorded elsewhere in pnpm-lock.yaml. Previously, snapshots for the platform-specific subdeps pulled in via a config dep's optionalDependencies were written as empty objects.
  • Fixed pickRegistryForPackage returning the wrong registry for an unscoped npm: alias under a scoped local name. A manifest entry like "@private/foo": "npm:lodash@^1" was routing the lodash fetch through registries["@private"], even though lodash is unscoped.
  • Don't print Installing config dependencies... when config dependencies are already installed and nothing needs to be fetched, re-linked, or removed.

11.2.2

  • When the install engine is delegated to pacquet via configDependencies, the user's CLI flags passed to pnpm install (e.g. --no-runtime, --prod, --dev, --no-optional, --node-linker, --cpu / --os / --libc, --offline, --prefer-offline) are now forwarded to pacquet's install subcommand verbatim. Previously pacquet was invoked with a fixed argument list, so flags like --no-runtime were silently dropped. Flag forwarding is gated on the command being install / i; add, update, and dedupe still don't forward (their flag surface doesn't line up with pacquet's install).
  • Fixed pnpm up (and pnpm add / pnpm remove) failing with pacquet_package_manager::outdated_lockfile when pacquet is declared in configDependencies. pnpm now passes --ignore-manifest-check to pacquet so its --frozen-lockfile check doesn't fire against the (pre-mutation) package.json pnpm hasn't written yet #11797.