Skip to content

fix: resolve pnpm content-addressable store packages in vxrn patch#692

Open
lightstrike wants to merge 1 commit intoonejs:mainfrom
lightstrikelabs:fix/pnpm-patch-resolution
Open

fix: resolve pnpm content-addressable store packages in vxrn patch#692
lightstrike wants to merge 1 commit intoonejs:mainfrom
lightstrikelabs:fix/pnpm-patch-resolution

Conversation

@lightstrike
Copy link
Copy Markdown
Contributor

Summary

  • pnpm store discoveryapplyDependencyPatches now globs .pnpm/<module>@*/node_modules to find packages that only exist in pnpm's content-addressable store (not hoisted to node_modules/ or .pnpm/node_modules/). This fixes silent patch failures in pnpm monorepos with strict hoisting, peer dep conflicts, or hoist=false.
  • Real-path deduplication — resolves symlinks before patching to prevent double-patching when node_modules/<module> symlinks and .pnpm/<store>/node_modules/<module> directories point to the same physical files. Critical for non-idempotent transforms like ['jsx'] and ['flow'].
  • Zero overhead for non-pnpm — the store scan is gated behind existsSync(.pnpm), so npm/yarn/bun users see no change.

Context

We hit this in a pnpm monorepo (lightstrikelabs/lightstrike-starter#35) where the built-in @react-navigation/core exports patch was silently skipped because the package wasn't hoisted — it only lived at .pnpm/@react-navigation+core@7.16.1_<hash>/node_modules/@react-navigation/core/. The workaround was a manual patchedDependencies entry in package.json. This PR eliminates that workaround by teaching vxrn to discover packages inside pnpm's store.

Changes

packages/vxrn/src/utils/patches.ts:

  • Added moduleToPnpmStorePattern() helper (@scope/name@scope+name)
  • Expanded nodeModulesDirs construction to glob pnpm store entries per patch module
  • Added patchedRealPaths Set with realpathSync dedup before patch application

packages/vxrn/src/utils/patches.test.ts (new):

  • moduleToPnpmStorePattern unit tests (scoped + unscoped)
  • pnpm store discovery for non-hoisted packages
  • Dedup when symlink + store entry resolve to same files
  • Flat node_modules regression (non-pnpm)
  • Version constraints across multiple store versions
  • Hoisted + store coexistence dedup

Test plan

  • All 8 new tests pass (npx vitest run src/utils/patches.test.ts)
  • TypeScript type check clean (tsc --noEmit)
  • Verify in a pnpm monorepo: remove manual patchedDependencies workaround, run one dev, confirm @react-navigation/core exports patch is applied
  • Verify existing non-pnpm examples (one-basic) still work with one patch

applyDependencyPatches now globs .pnpm/<module>@*/node_modules to discover packages that aren't hoisted to node_modules/ or .pnpm/node_modules/. Adds real-path deduplication to prevent double-patching when symlinks and store entries resolve to the same files. Includes tests for store discovery, dedup, version constraints, and flat node_modules regression.
@lightstrike
Copy link
Copy Markdown
Contributor Author

@natew Would appreciate your review on this when you get a chance. This fixes silent patch failures in pnpm monorepos — we hit it in our starter repo and had to work around it with a manual patchedDependencies entry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant