fix(shared): share React contexts across duplicate module instances#9180
fix(shared): share React contexts across duplicate module instances#9180alexcarpenter wants to merge 1 commit into
Conversation
createContextAndHook called React.createContext at module load, so a bundler that produced two instances of @clerk/shared/react (e.g. Vite/ Rolldown pre-bundling it separately from ClerkProvider) created two distinct context objects. A provider from one instance and a useClerk/ use*Context hook from another then failed to match and threw '... not found'. Cache contexts on a globalThis registry keyed by package version + display name so duplicated instances share one object.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: c502059 The changes in this PR will be included in the next version bump. This PR includes changesets to release 23 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
Stacked on #9144 (
carp/profile-release).Problem
The composed profile exports (
@clerk/ui/experimental) throwuseClerk can only be used within the <ClerkProvider /> componentunder TanStack Start (Vite v8 / Rolldown), while Next.js and React Router work.Root cause is not the components.
createContextAndHookcallsReact.createContext(...)at module load, and React matches a provider to a consumer by the identity of that context object. TanStack Start's Rolldown dep-optimizer pre-bundled@clerk/ui/experimentalas its own entry and inlined a second copy of@clerk/shared/react, whileClerkProvider(@clerk/tanstack-react-start, served as raw ESM) used the original copy. Two module instances → twoClerkInstanceContextobjects → the provider and the panels'useClerknever match.React Router avoids it only incidentally: its Vite build uses the esbuild optimizer, which bundles the provider and panels together and hoists one shared
@clerk/sharedchunk.Fix
Cache each context created by
createContextAndHookon aglobalThisregistry, keyed byPACKAGE_VERSION+ display name, so duplicated instances of@clerk/shared/reactshare one context object. This fixes the whole class of duplicate-instance mismatches for any bundler, not just Rolldown, and removes the need for consumer-sideoptimizeDeps/dedupeworkarounds.@clerk/sharedmajors from colliding.globalThis.__clerk_*singleton precedent in the repo (keyless devCache/logger).<Provider>.Tests
New
createContextAndHook.test.tsx:Full
@clerk/sharedreact suite passes (192 tests), lint + prettier clean.