From 07bf286c7b143e6ae285df66181102d0ac3ceb9e Mon Sep 17 00:00:00 2001 From: Neil <4138956+nwparker@users.noreply.github.com> Date: Sun, 18 Oct 2026 22:32:45 -0700 Subject: [PATCH] build: use the shared pnpm store on Windows by default (#30565) Without the symlink privilege pnpm links the global virtual store with junctions, which standard users can create. Verified on Windows 10.0.26200 at medium integrity with no SeCreateSymbolicLinkPrivilege and Developer Mode off: the install, both native runtime checks, a ConPTY spawn and windows-process-tree all pass. ORCA_PNPM_GLOBAL_VIRTUAL_STORE=0 still opts out; CI stays off. --- .github/CONTRIBUTING.md | 10 +++--- config/pnpmfile.cjs | 12 +++---- .../pnpmfile-global-virtual-store.test.mjs | 35 +++++++++---------- pnpm-lock.yaml | 2 +- 4 files changed, 26 insertions(+), 33 deletions(-) diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index de0f1ba7b84..d92892a425e 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -37,12 +37,12 @@ In PowerShell, use `$env:ORCA_DEV_MAIN_SOURCEMAPS='0'` before `pnpm dev`. Remove the variable when debugging the main process with source maps. Renderer and preload settings are unaffected; production builds always keep their hidden main maps. -On macOS and Linux, installs use pnpm's global virtual store: each package version is one slot +Local installs use pnpm's global virtual store: each package version is one slot under `~/pnpm/store` that every worktree links to, instead of a full `node_modules` per worktree. An existing worktree converts on its next `pnpm install`, and an older branch without the setting -converts back the same way. CI always uses the normal layout. Windows does too unless you set -`ORCA_PNPM_GLOBAL_VIRTUAL_STORE=1`, because its store links are real symlinks, which may need -administrator rights or Developer Mode. Things to know: +converts back the same way. CI always uses the normal layout. On Windows, pnpm links with +junctions when you lack the symlink privilege, so no administrator rights or Developer Mode are +needed. Things to know: - Keep `~/node_modules` (and any other `node_modules` above the store) out of your home directory. Node resolves upward from the store slot, so a stray one there supplies @@ -51,7 +51,7 @@ administrator rights or Developer Mode. Things to know: - Native addons are never rebuilt in place in a shared slot: each CPU gets its own build beside it (see [`native-build-entry.cjs`](../config/scripts/native-build-entry.cjs)), so cross-arch packaging is safe for other worktrees. -- `ORCA_PNPM_GLOBAL_VIRTUAL_STORE=1` opts in on Windows and `=0` opts out anywhere. Keep it set +- `ORCA_PNPM_GLOBAL_VIRTUAL_STORE=0` opts out. Keep it set in your shell: `pnpm run` re-checks the install and relinks a worktree whose layout no longer matches. diff --git a/config/pnpmfile.cjs b/config/pnpmfile.cjs index 8b88ee79432..0a9bba4f0b8 100644 --- a/config/pnpmfile.cjs +++ b/config/pnpmfile.cjs @@ -15,18 +15,14 @@ function isCi(env) { * * Off under CI, which packages from, caches, and verifies a project-local node_modules, unless * `ORCA_PNPM_FORCE_GLOBAL_VIRTUAL_STORE_IN_CI=1` (the dependency-isolation job). - * Windows needs `ORCA_PNPM_GLOBAL_VIRTUAL_STORE=1` because its store links are true symlinks, - * unverified for users without admin or Developer Mode; `=0` opts out anywhere else. + * On everywhere else, including Windows: without the symlink privilege pnpm links with + * junctions, which standard users can create. `ORCA_PNPM_GLOBAL_VIRTUAL_STORE=0` opts out. */ -function usesGlobalVirtualStore({ env = process.env, platform = process.platform } = {}) { +function usesGlobalVirtualStore({ env = process.env } = {}) { if (isCi(env)) { return env[FORCE_IN_CI_ENV] === '1' } - const choice = env[GLOBAL_VIRTUAL_STORE_ENV] - if (choice === '0' || choice === '1') { - return choice === '1' - } - return platform !== 'win32' + return env[GLOBAL_VIRTUAL_STORE_ENV] !== '0' } module.exports = { diff --git a/config/scripts/pnpmfile-global-virtual-store.test.mjs b/config/scripts/pnpmfile-global-virtual-store.test.mjs index 902874011cd..71e2ed3142b 100644 --- a/config/scripts/pnpmfile-global-virtual-store.test.mjs +++ b/config/scripts/pnpmfile-global-virtual-store.test.mjs @@ -11,26 +11,23 @@ const { describe('usesGlobalVirtualStore', () => { const cases = [ - // [env, platform, expected] - [{}, 'darwin', true], - [{}, 'linux', true], - [{}, 'win32', false], - [{ [STORE_ENV]: '1' }, 'win32', true], - [{ [STORE_ENV]: '0' }, 'win32', false], - [{ [STORE_ENV]: '0' }, 'darwin', false], - [{ [STORE_ENV]: 'yes' }, 'linux', true], - [{ CI: 'true' }, 'darwin', false], - [{ CI: '1' }, 'linux', false], - [{ GITHUB_ACTIONS: 'true' }, 'linux', false], - [{ CI: 'true', [STORE_ENV]: '1' }, 'win32', false], - [{ CI: 'true', [FORCE_IN_CI_ENV]: '1' }, 'linux', true], - [{ GITHUB_ACTIONS: 'true', [FORCE_IN_CI_ENV]: '1' }, 'win32', true], - [{ [FORCE_IN_CI_ENV]: '1', [STORE_ENV]: '0' }, 'darwin', false], - [{ CI: 'false' }, 'darwin', true], - [{ CI: '0' }, 'linux', true] + // [env, expected]; platform-independent, so Windows standard users get it too. + [{}, true], + [{ [STORE_ENV]: '1' }, true], + [{ [STORE_ENV]: '0' }, false], + [{ [STORE_ENV]: 'yes' }, true], + [{ CI: 'true' }, false], + [{ CI: '1' }, false], + [{ GITHUB_ACTIONS: 'true' }, false], + [{ CI: 'true', [STORE_ENV]: '1' }, false], + [{ CI: 'true', [FORCE_IN_CI_ENV]: '1' }, true], + [{ GITHUB_ACTIONS: 'true', [FORCE_IN_CI_ENV]: '1' }, true], + [{ [FORCE_IN_CI_ENV]: '1', [STORE_ENV]: '0' }, false], + [{ CI: 'false' }, true], + [{ CI: '0' }, true] ] - it.each(cases)('env %j on %s -> %s', (env, platform, expected) => { - expect(usesGlobalVirtualStore({ env, platform })).toBe(expected) + it.each(cases)('env %j -> %s', (env, expected) => { + expect(usesGlobalVirtualStore({ env })).toBe(expected) }) }) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86dc68f19f2..b36756f4dbb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -169,7 +169,7 @@ overrides: packageExtensionsChecksum: sha256-TrarseUCmMKP0lVjkfyLP2TAvkGZMZzvzPxjKY48nrY= -pnpmfileChecksum: sha256-568iOYVj6ZdABzEY52uLAgKwLTmlyqdEBiaV2dJCY74= +pnpmfileChecksum: sha256-6l6qdgUHKyTLYIQLx/UGfGRnEiFXxIaSlGMgK4mttEw= patchedDependencies: '@vscode/windows-process-tree@0.8.0': a09f2e8b2b4e73ef20c317af91f9e06c09abf62fa2c891d99b16f53047f596fd