Hoisted workspace materializes the same React version twice when an earlier importer pins another version #1293
Unanswered
mwolson
asked this question in
Troubleshooting and Bugs
Replies: 1 comment
|
Confirmed — this is a bug in the workspace hoist winner selection. The linker let the first importer in path order claim the root name slot, while pnpm/Yarn prefer an explicit root dependency and otherwise rank versions by distinct dependents plus peer dependents. PR #1296 adds that preference pass and regression coverage: #1296 I also verified the public reproduction directly: AI-assisted — Tool: Codex; model: unavailable; version: unavailable. |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Summary
In a two-importer workspace under
node-linker=hoisted, aube lets the alphabetically earlier importer claim the workspace-rootreactslot. A later importer that pins a different React version, plus a hoisted peer-dependent package resolved in that later importer's peer context, then get two distinctreact@<later>package-root realpaths. Node loads two module identities of the same version. Native pnpm hoisted places the later version once at the workspace root and nests only the earlier pin.This is not explained by incompatible peer ranges.
zustand@5.0.11declaresreact: ">=18.0.0"(optional). Both19.2.3and19.2.6satisfy that range.Minimal graph
Public packages only:
packages/mobiledepends onreact@19.2.3packages/webdepends onreact@19.2.6andzustand@5.0.11packages/mobileis earlier thanpackages/webin path order, which is what triggers aube's current root winner. Renaming the19.2.3importer topackages/zzzmakes aube match pnpm.Repro
https://github.com/mwolson/tmp-aube-issues/tree/main/hoisted-react-peer-duplication
git clone https://github.com/mwolson/tmp-aube-issues.git cd tmp-aube-issues/hoisted-react-peer-duplication ./repro.shThe script exits 0 when web and zustand resolve to the same
reactpackage-root realpath, and 1 when they do not. Isolated is the setup control and passes. Hoisted fails on aube 1.40.0.Direct commands:
Aube 1.40.0 hoisted placements
From
node_modules/.aube-state/hoisted-placements.json:{ "react@19.2.3": ["node_modules/react"], "react@19.2.6": [ "packages/web/node_modules/react", "node_modules/zustand/node_modules/react" ], "zustand@5.0.11(react@19.2.6)": ["node_modules/zustand"] }require("react")frompackages/weband fromnode_modules/zustandreturns different module exports. Isolated aube on the same manifests returns the same export.Native pnpm hoisted (
nodeLinker: hoisted)pnpm 11.21.0
node_modules/.modules.yaml:{ "nodeLinker": "hoisted", "hoistedLocations": { "react@19.2.6": ["node_modules/react"], "react@19.2.3": ["packages/mobile/node_modules/react"], "zustand@5.0.11(react@19.2.6)": ["node_modules/zustand"] } }pnpm 10.24.0 records the same locations. Web and zustand both resolve to the single root
react@19.2.6and share one module export.Why this is not just "two React versions in one workspace"
Two exact React pins are an intentional workspace fact. Isolated aube already isolates them correctly: one
react@19.2.6identity for web plus zustand, andreact@19.2.3for mobile.The hoisted failure is the extra split of
react@19.2.6into two package roots after19.2.3occupies the workspace root. #1243 share hoisted deps already says compatible dependencies should share one physical package at the root when they can, and that version or peer-context conflicts remain nested. Nesting19.2.3vs19.2.6is expected. Materializing19.2.6twice is the part that differs from pnpm and that produces two React identities in one web runtime.Questions
All reactions