Saltar al contenido principal

pnpm 12.7

· 12 min de lectura
Zoltan Kochan
Lead maintainer of pnpm

pnpm 12.7 lets the global node shim follow .nvmrc and .node-version, adds pnpm install --allow-build and pnpm publish --publish-wait-timeout, and creates pnpm-workspace.yaml from the workspaces field of package.json. pnpm install --force no longer installs optional dependencies built for other platforms. This release also carries security fixes and a long list of bug fixes.

Minor Changes​

.nvmrc and .node-version in the node shim​

The project-aware global node shim now uses the Node.js version from the nearest .nvmrc or .node-version file when the project does not declare a Node.js runtime in devEngines.runtime or engines.runtime (#4471). A project set up for nvm, fnm, or n gets the right node without further setup:

cd ~/projects/legacy-app
cat .nvmrc # 20
node --version # v20.x.x

The nearest directory with a Node.js runtime declaration decides the version. Within one directory, package.json takes precedence over .node-version, which takes precedence over .nvmrc. An .nvmrc value that only nvm can act on, such as system or a custom alias, is ignored. See .nvmrc and .node-version.

pnpm install --allow-build​

pnpm install --allow-build allows or denies a package's lifecycle scripts and records the decision in allowBuilds, as pnpm add --allow-build already did (#15388):

pnpm install --allow-build=esbuild --allow-build='!core-js'

Waiting for published packages​

pnpm publish --publish-wait-timeout <milliseconds> waits for the published versions and their tarballs to become available from the registry. A recursive publish confirms each package before it publishes the packages that depend on it, so a dependent never points at a version its consumers cannot fetch yet. If confirmation times out, the command fails. Set a default in pnpm-workspace.yaml:

pnpm-workspace.yaml
publishWaitTimeout: 60000

When pnpm publish -r --report-summary fails after some uploads were accepted, the summary file now lists those packages.

pnpm-workspace.yaml from the workspaces field​

In a repository with no pnpm-workspace.yaml, pnpm install now creates one from the workspaces field of the root package.json and links the listed projects on that same install (#2255). An existing pnpm-workspace.yaml is never changed, and nothing is created with --ignore-workspace. If the workspaces field later differs from packages in pnpm-workspace.yaml, pnpm prints a warning. See Converting from the workspaces field.

--force keeps skipping foreign optional dependencies​

pnpm install --force now keeps skipping optional dependencies whose os, cpu, or libc do not match the host (#6133). It still refetches every package and lifts engineStrict. The new forceIgnoresPlatform setting restores the previous behaviour:

pnpm-workspace.yaml
forceIgnoresPlatform: true

Other changes​

  • When a project pins a pnpm version or a runtime that another pnpm process is installing at that moment, pnpm now waits a few seconds and then installs and runs a private copy. It used to wait up to five minutes and then use the shared install directory without the lock. pnpm store prune removes any private copy a killed process left behind (#15413).
  • pnpm now keeps the blank lines between entries of package.json when it updates the file (#5602).
  • pnpm now reads and updates package.json5 manifests, keeping their comments. Workspace discovery prefers package.json, then package.json5, then package.yaml (#15129).
  • pnpm init --bare creates a package.json with only the required fields (#15538).
  • The reporter setting is now honored from pnpm-workspace.yaml, the global configuration, and PNPM_CONFIG_REPORTER (#4879).
  • Configuration files support npm's ${VAR?} placeholder, which expands to an empty string without a warning when VAR is unset (#14404).
  • publishConfig["@scope:registry"] now sets the publish registry of a scoped package (#12071).
  • Node.js runtime resolution supports Windows ARM64 (#7123).

Security​

  • pnpm no longer expands environment variables in a userAgent set in a project's pnpm-workspace.yaml. Such a userAgent is ignored. Before, pnpm sent the variable's value to the configured registry (#15415).
  • On Nix, a dependency's bin named like a system utility such as sed can no longer redirect a POSIX bin shim or the pnpm, pn, pnpx, and pnx launchers. Installing again replaces the shims already in node_modules (#14883).
  • pnpm no longer treats manifests inside its store, cache, state, or modules directories as workspace projects. A storeDir inside the workspace could let lifecycle scripts of packages in the store run without allowBuilds approval (#15033).
  • Packages that run a lifecycle script are no longer hard-linked into the virtual store, so a build script can no longer rewrite the workspace source of an injected package or the store copy it was imported from (#15483).

Patch Changes​

Installing​

  • Fixed running out of memory when many packages share a missing peer dependency, mostly with autoInstallPeers: false (#15362).
  • pnpm no longer hangs for up to 5 minutes after a pnpm process was killed while setting up the pinned pnpm version. A lock whose owner is gone is taken over at once (#15360).
  • Requests to a server whose TLS certificate fails verification now fail at once instead of being retried for more than a minute (#9134).
  • On macOS, pnpm falls back to its bundled CA roots when system trust evaluation is unavailable, such as in a sandbox (#15329).
  • A warm install uses less CPU while linking packages. On Windows, it could take several times longer than with pnpm 11 (#15439).
  • pnpm install now fetches committed submodules of git dependencies (#1470).
  • A local tarball replaced at the same path is reinstalled, and --frozen-lockfile rejects it (#2437, #1889).
  • Installs that skip devDependencies no longer run pnpm:devPreinstall or prepare scripts (#7065).
  • --prod installs no longer install a devDependency that only satisfies an optional peer of a production dependency (#15344).
  • pnpm fetch also installs the pnpm version pnpm-lock.yaml pins, so a later pnpm install --offline can switch to it (#11808).
  • pnpm install no longer adds allowBuilds placeholders to pnpm-workspace.yaml in CI or without a terminal (#11574).
  • pnpm detects the same CI environments as pnpm 11, including AWS CodeBuild.

Resolving and linking​

  • A dependency that a package also declares as an optional peer dependency is installed again, for example lightningcss in some vite builds (#8912).
  • Removing an entry from overrides now re-resolves the packages it targeted (#4587).
  • With trustPolicy: no-downgrade, pnpm resolves the newest matching version that is not a trust downgrade instead of failing (#14176).
  • autoDedupe and pnpm dedupe move transitive dependencies to the version a catalog: dependency pins, and pnpm dedupe no longer alternates between two lockfiles when an npm: alias is involved (#15588).
  • pnpm install --ignore-pnpmfile keeps pnpmfileChecksum in an up-to-date lockfile (#10944).
  • With nodeLinker: hoisted, hoistWorkspacePackages links selected workspace projects and their bins into the root node_modules (#7553), and removed packages' commands are removed from node_modules/.bin (#7568).
  • Installing the node package on Windows works again (#15501).

Workspaces and filtering​

  • Workspace projects reached through a symlink are installed (#1044).
  • A catalog: dependency whose entry points at a workspace project counts as a workspace dependency for ordering and filtering (#15587).
  • workspace: ranges match projects with non-semver versions such as 1.0 (#4567) and with build metadata (#6483).
  • --frozen-lockfile fails when the lockfile lists a workspace project that is missing (#7667).
  • Injected workspace packages get the output of their own prepare, install, and postinstall scripts (#9464).
  • A custom modulesDir works with several path segments, with nodeLinker: hoisted, and on the up-to-date fast path (#15484).
  • pnpm warns when a workspace install covers a project that has its own pnpm-workspace.yaml (#11724).
  • [<since>] compares against the merge base, and selects projects whose catalog versions changed (#9907, #8718).
  • --filter selectors are evaluated in order, so a later inclusion can re-include an excluded project (#9354).

Adding, updating, and removing​

  • pnpm add saves package.json before running lifecycle scripts (#8627) and saves a requested exact version (#6040).
  • pnpm add <pkg>@<version> and pnpm update <pkg>@<version> move a catalog entry onto the named version (#13715).
  • pnpm update keeps a range without a save prefix, such as <= 3.0.0, when the new version still satisfies it (#6714).
  • pnpm update <pkg> can move off a locked version the registry no longer serves (#9953).
  • pnpm unlink removes the link: dependency that pnpm link <dir> added (#4219).
  • pnpm install prunes unreferenced catalog entries when catalogPrune: true is set (#15273).
  • pnpm import converts Yarn's patch: protocol (#10278).
  • pnpm patch and pnpm patch-commit work with sharedWorkspaceLockfile: false (#9926).

Running scripts​

  • A script run without a terminal ends when pnpm is killed, for example by Playwright's webServer (#15555).
  • pnpm --filter <project> <command> and pnpm -r <command> run a command from the projects' dependencies when no script has that name (#10151).
  • pnpm exec and pnpm dlx set npm_execpath, INIT_CWD, npm_node_execpath, and NODE (#7037), and pnpm exec sets PWD (#1550).
  • pnpm restart runs stop and start when there is no restart script (#4750).
  • pnpm dlx keeps a separate cache entry per Node.js major version (#8611).
  • pnpm pipeline runs outside a Git work tree, without caching (#15601).
  • A runtime: range such as ^22.18.0 || ^24.0.0 installs the runtime instead of the node npm package (#14817).

Publishing and deploying​

  • pnpm publish resolves workspace: dependencies without node_modules (#6567).
  • pnpm pack and pnpm publish include bundled dependencies with the isolated linker (#1643), keep symlinks inside the package (#8208), and preserve executable permissions.
  • pnpm deploy copies the root packageManager field (#9079), honors virtualStoreDir (#8787), and skips the deployed project's prepare script (#7282).

Global packages and pnpm versions​

  • Global commands run with the pnpm you invoked, even in a project that pins another version (#14531).
  • pnpm self-update inside a project that pins pnpm also updates the global pnpm (#14747) and no longer leaves the previous @pnpm/exe behind (#14709).
  • pnpm setup no longer fails with Text file busy (#15494) and no longer deletes lines near the pnpm block of a shell startup file (#7067).

Windows and WSL​

  • Installs and pnpm clean wait for a file held open by another process instead of failing at once, on Windows (#15081) and on Windows drives under WSL (#6155).
  • Saving pnpm-lock.yaml is retried while another process holds it open (#9461).
  • Trailing dots and spaces are escaped in node_modules/.pnpm directory names (#8101).
  • Bin shims run from Git Bash, MSYS2, or Cygwin pass NODE_PATH as Windows paths (#3360).

Inspecting dependencies​

  • pnpm audit honors --filter (#10982) and lists a dependency path from every affected workspace project (#12200).
  • pnpm list and pnpm licenses list inside a workspace project list only that project (#14494, #5689).
  • pnpm list --only-projects prints every selected project (#9770).
  • pnpm licenses list works with sharedWorkspaceLockfile: false (#10140) and with nodeLinker: hoisted (#8589).
  • pnpm store status no longer reports packages with build scripts as modified (#15383).

See the v12.7.0 release notes for the complete list of changes.