Aller au contenu principal

pnpm 12.4

· 11 minutes de lecture
Zoltan Kochan
Lead maintainer of pnpm

pnpm 12.4 installs crates and Python packages next to npm packages in the same workspace, adds pnpm pipeline to run a workspace's tasks the way a CI job would, and ships binaries for six more platforms. pnpr 0.1.0-alpha.11, released alongside 12.4.1, serves Cargo, Python, and container registries beside npm, publishes across all of them in one transaction, and signs users in through OIDC.

Minor Changes

One workspace, three ecosystems

pnpm can now manage npm, Python, and Cargo dependencies in the same workspace. Enable cargo.enabled or python.enabled in pnpm-workspace.yaml, then install them all with one pnpm install.

pnpm-workspace.yaml
cargo:
enabled: true
python:
enabled: true
pnpm add crate:serde
pnpm add pypi:httpx
pnpm install

Each ecosystem keeps its own semantics. Cargo dependencies live in Cargo.toml and Cargo.lock, resolve against crates.io or the sparse registry named by cargo.indexUrl, and are vendored into a Cargo directory source that pnpm wires up through .cargo/config.toml. Crates pinned to a git revision, through a git dependency or [patch.crates-io], are checked out and vendored the way cargo vendor lays them out. Registry authentication goes through pnpm's own credentials, plus CARGO_REGISTRY_TOKEN or $CARGO_HOME/credentials.toml for crates.io.

Python dependencies live in pyproject.toml and a standard pylock.toml, with a managed .venv per project that pnpm run and pnpm exec put on PATH. The lockfile format was validated independently with uv.

What is shared is everything below the ecosystem boundary: one HTTP and authentication budget, one verified-artifact ingestion path, one content-addressable store. Frozen and offline installs work for all three, and both new ecosystems can offload resolution to pnprServer, falling back to local resolution when the server does not serve it (#14566).

This is early. The settings and the layout pnpm writes may still change.

pnpm pipeline

pnpm pipeline [name] installs frozen dependencies and runs a named set of workspace tasks. It selects the affected projects, runs their task graph, and keeps going after a task fails, so one run reports every failure rather than the first.

pnpm-workspace.yaml
tasks:
build:
dependsOn: ['^build']
outputs: ['dist/**']
test:
dependsOn: ['build']
outputs: []

pipelines:
default: [build, test]

Declaring outputs is what makes a task cacheable, outputs: [] included as the positive statement that a task writes no files. inputs narrows the key, env adds environment values to it, and cache: false opts back out. A hit restores the output files and replays the log.

Cargo tasks can reuse local build state between worktrees through tasks.<name>.cargoTargetDir, and pnpm pipeline --dry-run prints the graph without installing anything or running a hook.

Six more platforms

pnpm 12.4 ships binaries for Android on arm64 and x64, FreeBSD on x64, and Linux on ppc64le, s390x, and RISC-V. See supported platforms for the full list (#14431, #14597, #7582).

trustPolicyExcludePrune

trustPolicyExcludePrune removes the entries of trustPolicyExclude that the freshly written lockfile no longer resolves. It is off by default. Name patterns such as @scope/* are kept, and the cleanup is skipped when sharedWorkspaceLockfile is false.

pnpm change check

pnpm change check validates the versions committed in the workspace against the versioning.epics bands and versioning.fixed groups. It reads no change intents, so it belongs in CI on every pull request. Every violation is reported, including ones in packages the current release does not touch.

Registry metadata is keyed by the full URL

Registry metadata is now kept separate for registries that differ in URL path or scheme. That stops an install using another registry's package versions or tarball URLs, and stops metadata fetched over HTTP being reused for HTTPS (#13558).

The first install after upgrading refetches registry metadata; the package store is untouched. pnpm cache view now shows full registry URLs, so a script that parses the directory names out of pnpm cache list-registries or pnpm cache list needs updating.

Other changes

  • A patch that adds a build script or a binding.gyp now makes the package buildable, subject to build approval. Until it is approved, the package is listed under "Ignored build scripts" (#14648).
  • pnpm add --allow-build=!<pkg> rejects a build before the package is installed, global installs included, and pnpm approve-builds <pkg> saves a decision even when nothing is awaiting approval (#14067).
  • A registry configured in .npmrc outranks a route pnpm login saved in the global config.yaml, so logging in cannot redirect a project that names its registry (#14614).
  • fetchTimeout now limits how long a request may go without making progress, so a large download over a slow connection is no longer cut off while data is still arriving (#14604).
  • pnpm add --workspace <pkg> works again, saving the dependency with the workspace: protocol and failing when no workspace project provides it (#14602). Protocol-prefixed selectors such as jsr:@scope/pkg, npm:pkg@^1.0.0, and workspace:pkg@* are accepted too (#14590).
  • Boolean flags accept an explicit inline value: pnpm install --prod=false installs devDependencies (#14553).
  • Commands run from a project's subdirectory find the nearest ancestor with a manifest, so pnpm bin stops reporting paths under the wrong directory. pnpm init still creates its manifest where you stand, and pnpm exec still runs there (#14622).
  • pnpm patch-commit produces valid patches when files are added or deleted, and pnpm install accepts patches that delete files without listing their contents, and patch files with CRLF line endings (#14559, #14557).
  • Version ranges with partial upper bounds behave: <=16 includes every 16.x version (#14419).
  • Workspace package patterns accept . and .. segments and repeated slashes, so ./packages/* and !./packages/foo match (#14571).
  • packageConfigs settings apply to the projects they name when sharedWorkspaceLockfile is false, and a workspace on a shared lockfile is told which entries were ignored (#14556).
  • Invalid certificates in ca or cafile no longer fail the install with Invalid CA certificate; the valid ones still apply (#14646).
  • pnpm audit summaries exclude advisories ignored through audit.ignore and report them separately (#14535).
  • Shell completions cover the pn alias in bash, fish, pwsh, and zsh (#11955), and pnpm version accepts -m for --message (#14567).
  • Warm installs in workspaces with many projects are faster (#14540), and pnpm deploy is faster in large workspaces and no longer fails with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH when the project has a .pnpmfile.mjs (#14539, #14671).

12.4.1

The follow-up release fixes installs that failed on filesystems refusing hard links or clones, on Android, and under nodeLinker: hoisted, and makes repeat installs faster.

  • pnpm install copies a file instead of failing with Operation not permitted when the filesystem refuses a hard link or a copy-on-write clone, under packageImportMethod: auto and clone-or-copy (#14722). EdenFS checkouts, which have no hard links, and rootless containers, which refuse the clone syscall, both hit this. pnpm also copies a file whose store entry has reached the filesystem's limit on names for one file, 1024 on NTFS and 65000 on ext4.
  • Registry requests on Android crashed because pnpm found no system CA certificates, so it uses bundled ones there (#14777).
  • Under nodeLinker: hoisted, a repeat install no longer re-imports packages that are already in place. It used to replace the whole node_modules tree and report Packages: +N, lifecycle scripts included.
  • A build whose whole effect lands outside its own package directory, such as a git hook installer, runs again when its side-effects cache entry has no files to restore (#14717).
  • ignoredOptionalDependencies is applied by pnpm install, pnpm add, and pnpm dedupe. pnpm 12 installed those dependencies whenever it resolved from scratch (#14729).
  • Ctrl+C is passed on to the script pnpm started, and pnpm waits for it to shut down instead of exiting first and letting a still-writing script land on the shell prompt (#14723).
  • pnpm dedupe processes every workspace project by default, including workspaces that keep a lockfile per project (#14732).
  • The updateConfig pnpmfile hook receives the resolved configuration, with scoped registries under registriesByScope and credentials under configByUri (#14676).
  • Repeat installs are faster: the store's files are checked only for the packages pnpm links into node_modules, and creating the command shims makes about 1,500 fewer filesystem calls in a 76 project workspace (#14540).
  • pnpm warns when the root package.json declares a non-empty workspaces array and the project has no pnpm-workspace.yaml. Such an install linked no project and said nothing about why (#2255).

pnpr 0.1.0-alpha.11

Cargo, Python, and container registries

pnpr now serves Cargo and Python registries alongside npm from one instance. Hosted Cargo registries support cargo publish, cargo yank, cargo search, and crate downloads; hosted Python registries support pip install --index-url and twine upload. Upstream registries can proxy crates.io and PyPI with checksum-verified downloads, and one router can combine sources from all three ecosystems.

A registry that serves more than one ecosystem addresses them through /npm/, /cargo/, and /pypi/. A registry that serves only one keeps serving packages at the root, so existing npm URLs still work. Registry names can be reused across ecosystems by grouping configuration under registries.npm, registries.cargo, registries.pypi, or registries.oci.

Container images are the fourth ecosystem. Declare a registry with ecosystem: oci, then push to it with docker, podman, or skopeo. The distribution API answers at /v2/ on the host root, and an image keeps its own name with no registry key in the path. Ranged blob downloads, cross-repository blob mounts, the referrers API, and paginated tag and repository listings are supported, and pnpr can cache pulls from Docker Hub and GHCR with per-repository bearer tokens and digest verification (#14630).

PUT /-/pnpr/v0/publish publishes packages of more than one ecosystem in a single transaction, so a workspace that ships an npm package, a crate, and a Python distribution releases them together. A batch that fails a check publishes none of it, and a server that stops midway finishes the release on the next startup.

OIDC

pnpr supports OpenID Connect browser sign-in. Administrators map provider subjects to registry users, and GitHub Actions can publish npm packages without a persistent registry token, restricted to the packages you configure.

Builds, pipelines, and discovery

  • pnpr can share Cargo compilation caches between CI and developers through sccache, with read and publication access granted separately.
  • pnpr can store pnpm pipeline run reports, with a listing API, a detail API, and a web viewer. Records live with the hosted packages, so a run submitted through one replica is served by every other.
  • Browser registry UIs can be served through an origin allowlist, with paginated search, maintainer filters, organization listings, and per-registry upstream discovery. A registry directory endpoint lists the named registries, ecosystem endpoints, and routing order the caller can see.
  • Every command-line option can come from an environment variable named after the flag with a PNPR_ prefix, so --public-url becomes PNPR_PUBLIC_URL.

Fixes

  • A package name carrying ?, #, %, whitespace, or a control character is rejected, artifact filenames held to the same rule. A percent-encoded delimiter let a request read an upstream package under a name the access rules had not checked.
  • JSR packages resolve with no configuration: npm.jsr.io is a built-in public route, like the npm registry.
  • A staged publish is approved once, whichever replica of a shared registry the approval reaches; a second approval answers 409 (#12199).
  • A publish that loses a write race reports document_write_conflict on every registry surface, naming the package document (#14599).

For the complete client changes, see the v12.4.0 and v12.4.1 release notes. The server changes are in the pnpr 0.1.0-alpha.11 release notes.