vitejs / vitejs/vite-plugin-react
Dependency Optimizer: re-optimization can flip which duplicated chunk is "canonical" for a module, breaking module singletons (duplicate React on a cold-started dev server)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 1.2k
- Forks
- 269
- Avg merge
- 1d 3h
- Merged PRs (30d)
- 19
Description
Describe the bug
🤖 AI Disclosure: Claude Code has written up majority of this issue and most of the reproduction README. I, as a human, still take responsibility for it.
Summary
When two optimizeDeps.include entries resolve to the same module (e.g. react and @vitejs/plugin-rsc > react, where @vitejs/plugin-rsc can be any package that peer-depends on react), the optimizer emits two chunks for it — one holds the real module, the other re-exports it. Which one is "canonical" vs. the re-export is not stable across optimizer passes: a re-optimization can swap them.
| chunk | pass 1 (cold) | pass 2 (after re-optimization) |
|---|---|---|
react.js |
canonical | alias → @vitejs_plugin-rsc_n_react.js |
@vitejs_plugin-rsc_n_react.js |
alias → react.js |
canonical |
If that re-optimization is triggered after some modules have already been served (a dependency discovered at request time), a consumer loaded before the swap and one loaded after end up bound to two different real instances of the module. For React this is Invalid hook call / Cannot read properties of null (reading 'useState'); the page then auto-reloads (optimized dependencies changed. reloading) and the error vanishes — so it's cold-start-only, first-render-only.
Detailed explanation can be found in the reproduction repository's README.
Context
I've been developing a React framework based on @vitejs/plugin-rsc. This issue originally surfaced as a framework bug, but a thorough investigation made us believe that this is a Vite issue.
The repro still uses @vitejs/plugin-rsc because it is the way we are aware of for reliably reproducing the issue, but we believe this issue is in Vite's Deps Optimization, hence a bug report in this repo.
The trigger path (via @vitejs/plugin-rsc): a "use client" package imported by a server component is reached on the browser through a request-time virtual:vite-rsc/client-package-proxy/<pkg> module that the optimizer's initial scan can't follow — so the package (and the React it imports) is discovered on the first render and forces the re-optimization.
Side Note: possible another form of this bug
Initially this bug surfaced as a different error like this:
The requested module '/node_modules/.vite/deps/react_jsx-runtime.js?v=...' does not provide an export named 't'
a severer ES Modules link time error. This version of error is not included in this bug report because (1) we couldn't reproduce this without involving our framework and (2) we are not sure whether they are truly same origin. Read more about this at https://github.com/uhyo/funstack-static/issues/124 and https://github.com/uhyo/funstack-static/issues/128.
Reproduction
https://github.com/uhyo/vite-rsc-deps-issue-repro/tree/repro/duplicate-react-cold-start
Steps to reproduce
pnpm install && rm -rf node_modules/.vite && pnpm dev
# open the URL; first load throws Invalid hook call, then auto-reloads
System Info
System:
OS: Linux 6.18 Ubuntu 22.04.1 LTS 22.04.1 LTS (Jammy Jellyfish)
CPU: (16) x64 AMD Ryzen 7 PRO 6850U with Radeon Graphics
Memory: 12.37 GB / 15.01 GB
Container: Yes
Shell: 5.1.16 - /bin/bash
Binaries:
Node: 24.13.1 - /home/uhyo/.volta/tools/image/node/24.13.1/bin/node
Yarn: 4.1.1 - /home/uhyo/.volta/tools/image/yarn/4.1.1/bin/yarn
npm: 11.4.2 - /home/uhyo/.volta/tools/image/npm/11.4.2/bin/npm
pnpm: 10.30.1 - /home/uhyo/.volta/bin/pnpm
Deno: 2.2.1 - /home/uhyo/.deno/bin/deno
npmPackages:
@vitejs/plugin-react: latest => 6.0.3
@vitejs/plugin-rsc: latest => 0.5.27
vite: ^8.0.16 => 8.1.0
Used Package Manager
pnpm
Logs
No response
Validations
- Follow our Code of Conduct
- Read the Contributing Guidelines.
- Read the docs.
- Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- Make sure this is a Vite issue and not a framework-specific issue. For example, if it's a Vue SFC related bug, it should likely be reported to vuejs/core instead.
- Check that this is a concrete bug. For Q&A open a GitHub Discussion or join our Discord Chat Server.
- The provided reproduction is a minimal reproducible example of the bug.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked duplicate-react-cold-start reproduction and its README, then trace Vite's dependency-optimization re-optimization path and chunk canonicalization. Done means repeated optimizer passes keep the canonical mapping stable and the reproduction no longer creates duplicate React instances or the first-render invalid hook call.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript, vite
- Domain
- build-system, tooling
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100