mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[GH-ISSUE #409] Module duplication: client references resolve to raw ESM paths instead of pre-bundled paths #90
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#90
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @Jbithell on GitHub (Mar 10, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/409
Summary
When a React Server Component imports a
'use client'module (e.g. from@mantine/core), vinext creates client references that resolve to the raw ESM path (/node_modules/@mantine/core/esm/...). Meanwhile, client components that directly import the same package load from Vite's pre-bundled path (/node_modules/.vite/deps/@mantine_core.js).This creates two separate module instances in the browser, which means
createContext()is called twice, producing different React context objects. Any context provider using the pre-bundled copy is invisible to consumers using the raw ESM copy, and vice versa.Reproduction
@mantine/core(or any library that uses React context)MantineProvidervia a'use client'wrapper component<TextInput />Expected: TextInput renders correctly, finding MantineProvider in the component tree.
Actual: Error:
@mantine/core: MantineProvider was not found in component treeRoot cause
In Vite's dev mode, vinext runs three environments (RSC, SSR, client) with separate module graphs. When the RSC environment encounters a
'use client'import, it serialises a client reference containing the module's raw file path. On the client, this reference is loaded as a raw ESM module from the Vite dev server.However, the
MantineProvider(rendered by a client component in the layout) loads@mantine/corethrough Vite's dependency pre-bundling, which bundles the package into a single.vite/deps/@mantine_core.jsfile.The browser ends up loading both:
/node_modules/.vite/deps/@mantine_core.js(pre-bundled, used by client components)/node_modules/@mantine/core/esm/core/MantineProvider/MantineThemeProvider/MantineThemeProvider.mjs(raw ESM, used by client references from server components)These are separate JavaScript modules with separate
createContext()calls, so the React context set by one is not visible to the other.Workaround
Exclude the affected packages from Vite's dependency pre-bundling so all imports use raw ESM paths consistently:
This forces all
@mantineimports to use raw ESM, eliminating the duplication. The downside is significantly more HTTP requests in dev mode (500+ individual module files instead of one pre-bundled file).Suggested fix
Client references created by the RSC environment should resolve to the client environment's pre-bundled module paths (when available), rather than raw ESM file paths. This would ensure that both direct client imports and RSC client references load from the same module instance, preserving React context identity.
Environment