Description
core-web runs on pnpm 10.17.1. Since then pnpm has shipped two majors — 11.0.0 (2026-04-28) and 12.0.0 (2026-08-26, currently 12.4.2) — and both changed things that this repository depends on. The move is mostly mechanical, but it touches the same build and CI surface that PR #36169 (yarn 1 to pnpm 10 migration, merged 2026-06-16, 31 files) established, so that PR is the checklist for what has to be re-verified.
What actually changes
| Area |
pnpm 10 (today) |
pnpm 11 / 12 |
| Where settings live |
package.json#pnpm block (core-web/package.json:329-370) |
Not read any more. Everything moves to a new core-web/pnpm-workspace.yaml |
.npmrc |
registry + engine-strict + strict-peer-dependencies + fetch-timeout |
Auth and registry only. The other three are silently ignored unless moved |
| Build scripts allowlist |
onlyBuiltDependencies (11 packages) |
onlyBuiltDependencies, neverBuiltDependencies, ignoredBuiltDependencies, onlyBuiltDependenciesFile removed; replaced by the allowBuilds map |
| Distribution |
Single ~17 MB JS package |
Native Rust binary shipped through @pnpm/exe.* optional dependencies (3.9 MB wrapper). Corepack runs no lifecycle scripts, so under corepack the binary is downloaded on first use and signature-verified |
| Supply-chain defaults |
Opt-in |
minimumReleaseAge: 1440, blockExoticSubdeps: true, strictDepBuilds: true on by default |
verifyDepsBeforeRun |
false |
install (auto-installs before every pnpm run / pnpm exec) |
engineStrict |
warns on incompatible packages under optional subtrees |
fails the install (pnpm 12) — and this repo sets engine-strict=true |
Why now
- Deterministic lockfile (pnpm 12). Dependency cycles are broken canonically during peer resolution, so the lockfile becomes a pure function of the dependency graph. On cycle-heavy workspaces peer resolution is 2-3x faster, uses ~25% less memory and produces a smaller lockfile. This repo's lock is 33,442 lines / 3,011 packages with Angular 22 + PrimeNG + NgRx peer chains, which is exactly that shape.
- Install performance. SQLite-backed store index (store v11) instead of thousands of JSON files, bundled manifests, direct-to-CAS writes (~30k fewer rename syscalls per cold install), undici with Happy Eyeballs,
If-Modified-Since metadata fetches, and hardlink-before-clone on Linux.
- Supply-chain protection by default rather than as a follow-up nobody schedules.
- New tooling we can use in CI:
pnpm ci (clean + frozen install), pnpm sbom (CycloneDX 1.7 / SPDX 2.3), pnpm audit on GHSA identifiers with --fix=update.
- Staying on 10 only makes the eventual jump larger; 11 alone would be a toll booth, since 12 keeps 11's configuration model.
Registry mirror finding
Verified against both registries while scoping this work:
| Registry |
time (full doc) |
time (abbreviated) |
dist.attestations |
dist.signatures |
| registry.npmjs.org |
yes |
no |
yes |
yes |
| dotcms-npm.b-cdn.net |
no |
no |
yes |
yes |
minimumReleaseAge needs publish timestamps, so it cannot be evaluated through our mirror. With the default minimumReleaseAgeIgnoreMissingTime: true the check is skipped silently; setting it to false would fail every install. Attestations and signatures do pass through, so trustPolicy works. This task therefore hardens what is verifiable and opens a separate infrastructure issue for the mirror.
Decisions already taken
| Decision |
Choice |
| Target version |
Pin pnpm 12.4.2 (includes the executable-shim security fixes) |
| pnpm install strategy in Maven |
Decided by experiment in the POC: corepack (with download-on-first-use of the native binary) vs. npm-based install into installs/node. The outcome is documented in the PR |
| Supply-chain posture |
trustPolicy: no-downgrade, blockExoticSubdeps: true, strictDepBuilds: true. minimumReleaseAgeIgnoreMissingTime stays true, documented as a no-op until the mirror exposes time |
verifyDepsBeforeRun |
warn — reports drift without injecting an install into a Maven or CI build |
Acceptance Criteria
Configuration migration
Security posture
Build and CI
No regressions
Documentation
Priority
Medium
Additional Context
Description
core-webruns on pnpm 10.17.1. Since then pnpm has shipped two majors — 11.0.0 (2026-04-28) and 12.0.0 (2026-08-26, currently 12.4.2) — and both changed things that this repository depends on. The move is mostly mechanical, but it touches the same build and CI surface that PR #36169 (yarn 1 to pnpm 10 migration, merged 2026-06-16, 31 files) established, so that PR is the checklist for what has to be re-verified.What actually changes
package.json#pnpmblock (core-web/package.json:329-370)core-web/pnpm-workspace.yaml.npmrcengine-strict+strict-peer-dependencies+fetch-timeoutonlyBuiltDependencies(11 packages)onlyBuiltDependencies,neverBuiltDependencies,ignoredBuiltDependencies,onlyBuiltDependenciesFileremoved; replaced by theallowBuildsmap@pnpm/exe.*optional dependencies (3.9 MB wrapper). Corepack runs no lifecycle scripts, so under corepack the binary is downloaded on first use and signature-verifiedminimumReleaseAge: 1440,blockExoticSubdeps: true,strictDepBuilds: trueon by defaultverifyDepsBeforeRunfalseinstall(auto-installs before everypnpm run/pnpm exec)engineStrictengine-strict=trueWhy now
If-Modified-Sincemetadata fetches, and hardlink-before-clone on Linux.pnpm ci(clean + frozen install),pnpm sbom(CycloneDX 1.7 / SPDX 2.3),pnpm auditon GHSA identifiers with--fix=update.Registry mirror finding
Verified against both registries while scoping this work:
time(full doc)time(abbreviated)dist.attestationsdist.signaturesminimumReleaseAgeneeds publish timestamps, so it cannot be evaluated through our mirror. With the defaultminimumReleaseAgeIgnoreMissingTime: truethe check is skipped silently; setting it tofalsewould fail every install. Attestations and signatures do pass through, sotrustPolicyworks. This task therefore hardens what is verifiable and opens a separate infrastructure issue for the mirror.Decisions already taken
installs/node. The outcome is documented in the PRtrustPolicy: no-downgrade,blockExoticSubdeps: true,strictDepBuilds: true.minimumReleaseAgeIgnoreMissingTimestaystrue, documented as a no-op until the mirror exposestimeverifyDepsBeforeRunwarn— reports drift without injecting an install into a Maven or CI buildAcceptance Criteria
Configuration migration
core-web/pnpm-workspace.yamlexists and carriesoverrides,peerDependencyRules,ignoredOptionalDependencies,engineStrict,strictPeerDependenciesandfetchTimeout; thepnpmblock is gone fromcore-web/package.jsoncore-web/.npmrccontains only registry and auth settingsonlyBuiltDependenciesare expressed as anallowBuildsmap, andcanvaskeeps its explicit entry alongsideignoredOptionalDependenciescore-web/package.jsondeclarespackageManager: pnpm@12.4.2, andnodejs-parent/pom.xmldeclares the same version, so the existing sync check inmaven-job/action.yml:213passespnpm installreports no unrecognized workspace settings (pnpm 12 fails withERR_PNPM_UNRECOGNIZED_WORKSPACE_SETTINGSwhen the project pins its pnpm version, so a leftover or misspelled key is caught here)Security posture
trustPolicy: no-downgrade,blockExoticSubdeps: trueandstrictDepBuilds: trueare set explicitly inpnpm-workspace.yamland a full install succeeds with themminimumReleaseAgeIgnoreMissingTimeis left at its default with a comment recording that our mirror stripstime, so the maturity check does not run todaydotcms-npm.b-cdn.netasking fortimeto be preserved in package metadata, and is linked from this issueverifyDepsBeforeRun: warnis set, and apnpm exec nxinvocation against a stalenode_moduleswarns instead of installingBuild and CI
pnpm/action-setupis bumped to v6.1.0 (the first release supporting pnpm 12) and pinned by commit SHA in bothmaven-job/action.ymlanddeploy-javascript-sdk/action.ymlpnpm install --frozen-lockfilesucceeds from a clean clone, and the install time is recorded against the pnpm 10 baselinepnpm exec nx run-many -t build --exclude='tag:skip:build'builds every project./mvnw -DskipTests install -pl :dotcms-core-web --am -Dmaven.build.cache.enabled=falsesucceeds from a clean statedotcms-postmanandapps/dotcms-ui-e2estill resolve${node.install.dir}/pnpmand run their install goalsdeploy-javascript-sdkis exercised in a dry run, since pnpm 11 replaced the npm-delegating publish flow with a native oneNo regressions
pnpm-lock.yamlis regenerated and the diff is reviewed: version changes are explained (pnpm 12 re-keys walk-order-dependent peer variants of cyclic packages once) and no dependency is unintentionally upgradedengineStrictdoes not newly fail the install; pnpm 12 turned the optional-subtree warning into an error, so any package it now rejects is triaged and resolvedDocumentation
core-web/CLAUDE.md,.github/copilot-instructions.mdand.github/instructions/frontend.instructions.mdreflect the new version and thepnpm-workspace.yamllocation for settingsstylus: github:stylus/stylus#0.59.0override is either removed or justified (stylus is an optional peer that is never installed, so the override resolves nothing today)Priority
Medium
Additional Context
codemod run pnpm-v10-to-v11(it movespackage.json#pnpmintopnpm-workspace.yaml, splits.npmrc, and collapses the build-dependency settings intoallowBuilds). It does not cover the CVE-to-GHSA rename or anything Maven-side.