Skip to content

[code-infra] Install pnpm over the image's copy instead of shimming it - #1832

Merged
Janpot merged 13 commits into
masterfrom
worktree-pnpm-standalone-install
Sep 3, 2026
Merged

Janpot merged 13 commits into
masterfrom
worktree-pnpm-standalone-install

Conversation

@Janpot

@Janpot Janpot commented Sep 2, 2026 •

Copy link
Copy Markdown
Member

Alternative to #1830.

cimg/node installs an unpinned pnpm next to the node binary, and that directory is searched before PATH by anything using npm-run-path. So publint 0.3.24, which now packs through the package manager, gets the image's pnpm rather than the pinned one, and COREPACK_ROOT stops it correcting itself. #1830 adds a third pnpm to node_modules/.bin to win that search; this installs the pinned version into that directory instead, so the pnpm found first is the right one.

Corepack goes with it, which pnpm now recommends against for CI and Node 25 no longer ships. Installing an exact version also stops pnpm forking a second pnpm on every call to switch to the one packageManager names, and a packageManager that doesn't name pnpm fails the step.

Verified on CI by temporarily pointing this repo's orb at the branch and printing what a rebuilt npm-run-path lookup resolves to (both commits since reverted). On cimg/node, /usr/local/bin/pnpm was the image's 11.18.0 and is now the pinned 11.22.0; on the Playwright executor the same holds at /usr/bin. Note that CI on a branch normally loads the orb from refs/heads/master, so changes to this file are not otherwise exercised here.

cimg/node runs an unpinned `npm install -g pnpm`, which lands next to the
node binary. That directory is the one npm-run-path rebuilds PATH from
before consulting the inherited PATH, so tools spawning `pnpm` that way
reach the image's version rather than the one `packageManager` pins.
publint 0.3.24 started packing through the package manager, which is how
this surfaced.

Remove that copy and install the pinned version with pnpm's standalone
script, which pnpm now documents for CI in place of corepack. Pinning
PNPM_VERSION lets pnpm skip its version switch rather than forking a
second pnpm on every invocation; where no pin is in reach it falls back
to switching itself.
@code-infra-dashboard

code-infra-dashboard Bot commented Sep 2, 2026 •

Copy link
Copy Markdown

Deploy preview

https://deploy-preview-1832--mui-internal.netlify.app/
QR code for https://deploy-preview-1832--mui-internal.netlify.app/

Bundle size

Total Size Change: 0B(0.00%) - Total Gzip Change: 0B(0.00%)
Files: 72 total (0 added, 0 removed, 0 changed)

Show details for 72 more bundles

@mui/internal-docs-infra/abstractCreateDemo parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/abstractCreateDemoClient parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/abstractCreateStream parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/abstractCreateTypes parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/ChunkProvider parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/cli parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeControllerContext parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeExternalsContext parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeHighlighter parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeHighlighter/errors parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeHighlighter/types parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CodeProvider parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CoordinatedLazy parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/CoordinatedLazy/types parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createDemoData parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createDemoData/types parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createSitemap parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/createSitemap/types parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCode parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCodeWindow parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCoordinated parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCopier parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useCrossTabState parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useDemo parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useDemoController parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useErrors parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useLocalStorageState parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/usePreference parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useScrollAnchor parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useSearch parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useSearch/types parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useStream parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useStream/types parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useType parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useTypes parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/useUrlHashState parsed: 0B(0.00%) gzip: 0B(0.00%)
@mui/internal-docs-infra/withDocsInfra parsed: 0B(0.00%) gzip: 0B(0.00%)
addLineGutters parsed: 0B(0.00%) gzip: 0B(0.00%)
BuildEngine parsed: 0B(0.00%) gzip: 0B(0.00%)
CodeHighlighterChunk parsed: 0B(0.00%) gzip: 0B(0.00%)
CodeHighlighterClient parsed: 0B(0.00%) gzip: 0B(0.00%)
CodeInitialSourceLoader parsed: 0B(0.00%) gzip: 0B(0.00%)
CodeSourceLoader parsed: 0B(0.00%) gzip: 0B(0.00%)
compileCssWithPostcss parsed: 0B(0.00%) gzip: 0B(0.00%)
computeHastDeltas parsed: 0B(0.00%) gzip: 0B(0.00%)
createFrame parsed: 0B(0.00%) gzip: 0B(0.00%)
createParseSourceWorkerClient parsed: 0B(0.00%) gzip: 0B(0.00%)
EditingEngine parsed: 0B(0.00%) gzip: 0B(0.00%)
embedTransforms parsed: 0B(0.00%) gzip: 0B(0.00%)
enhanceCodeEmphasis parsed: 0B(0.00%) gzip: 0B(0.00%)
findExpandingRanges parsed: 0B(0.00%) gzip: 0B(0.00%)
frameVisibility parsed: 0B(0.00%) gzip: 0B(0.00%)
getHastTextContent parsed: 0B(0.00%) gzip: 0B(0.00%)
grammarLoaders parsed: 0B(0.00%) gzip: 0B(0.00%)
grammars parsed: 0B(0.00%) gzip: 0B(0.00%)
isFrameSpan parsed: 0B(0.00%) gzip: 0B(0.00%)
loadCodeFallback parsed: 0B(0.00%) gzip: 0B(0.00%)
loadIsomorphicCodeVariant parsed: 0B(0.00%) gzip: 0B(0.00%)
parseSource parsed: 0B(0.00%) gzip: 0B(0.00%)
rolldown-runtime parsed: 0B(0.00%) gzip: 0B(0.00%)
source.css parsed: 0B(0.00%) gzip: 0B(0.00%)
source.js parsed: 0B(0.00%) gzip: 0B(0.00%)
source.json parsed: 0B(0.00%) gzip: 0B(0.00%)
source.mdx parsed: 0B(0.00%) gzip: 0B(0.00%)
source.shell parsed: 0B(0.00%) gzip: 0B(0.00%)
source.ts parsed: 0B(0.00%) gzip: 0B(0.00%)
source.tsx parsed: 0B(0.00%) gzip: 0B(0.00%)
source.yaml parsed: 0B(0.00%) gzip: 0B(0.00%)
text.html.basic parsed: 0B(0.00%) gzip: 0B(0.00%)
text.md parsed: 0B(0.00%) gzip: 0B(0.00%)
TransformEngine parsed: 0B(0.00%) gzip: 0B(0.00%)
transpileSource parsed: 0B(0.00%) gzip: 0B(0.00%)

Details of bundle changes

Performance

Total duration: 16.53 ms +0.47 ms(+2.9%) | Renders: 5 (+0) | Paint: 57.92 ms -2.97 ms(-4.9%)

Test Duration Renders
DataGrid mount with paint timing 2.08 ms 🔺+0.40 ms(+23.8%) 1 (+0)

6 tests within noise — details


Check out the code infra dashboard for more information about this PR.

Reading packageManager from the working directory forked the behaviour on
cwd: jobs starting in a nested directory found a package.json without the
field and silently installed an unpinned pnpm. Resolving from the git
toplevel gives every job the same pinned version, which is what corepack
did by walking up, and lets a missing field fail like a wrong one.

`rm -f` of the binaries next to node already covers the directory
npm-run-path probes; npm's global prefix is that same directory on
cimg/node, so `npm uninstall -g` only freed an unreachable package tree
at the cost of an npm start-up in every job on both executors.
@Janpot Janpot added the scope: code-infra Involves the code-infra product (https://www.notion.so/mui-org/5562c14178aa42af97bc1fa5114000cd). label Sep 2, 2026
@Janpot
Janpot requested a review from a team September 2, 2026 16:00
`pnpm setup` installs into PNPM_HOME and links the binaries in its `bin`
subdirectory, defaulting the former to the XDG data dir. The exports
written to BASH_ENV named neither: they pointed at ~/.pnpm, which nothing
creates, and omitted `bin`. Every step after the install then found no
pnpm on PATH.

Setting PNPM_HOME before the install makes the value the exports use the
same one `setup` acted on, rather than a guess made after the fact.
Both existed to prove the fix on CI: cimg/node ships pnpm 11.18.0 at
/usr/local/bin, which is the directory npm-run-path searches before PATH,
and after this change that lookup reaches the pinned 11.22.0 instead.
@Janpot
Janpot marked this pull request as ready for review September 3, 2026 05:22
@Janpot
Janpot merged commit b6e88e5 into master Sep 3, 2026
16 checks passed
@Janpot
Janpot deleted the worktree-pnpm-standalone-install branch September 3, 2026 05:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

scope: code-infra Involves the code-infra product (https://www.notion.so/mui-org/5562c14178aa42af97bc1fa5114000cd).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants