fix(react-start): Do not optimizeDeps in VITEST environment
Fix: Disable forced optimizeDeps in Vitest to prevent duplicate React instances
The Issue
When using @tanstack/react-start in a monorepo setup with Vitest, the plugin unconditionally adds react and react-dom to optimizeDeps.include. This forces Vite to pre-bundle React into an ESM wrapper (e.g., .vite/deps/react.js).
This causes a "Dual React Instance" conflict (leading to Invalid hook call errors) under the following common testing scenario:
-
Workspace Packages: Code transformed by Vitest (e.g., source code in a monorepo package) resolves
reactto the pre-bundled ESM version forced by the plugin. -
External Packages: Dependencies in
node_modules(e.g.,@testing-library/reactor UI libraries) are externalized by Vitest for performance. They use Node's native resolution, which resolvesreactto the standard CJS/ESM build innode_modules/react.
Because the pre-bundled React and the native React are different physical files/modules, they do not share the global ReactCurrentDispatcher. When a workspace component (using Pre-bundled React) is rendered by a test utility (using Native React), hooks fail.
The Fix
This PR updates the tanstackStart Vite plugin to skip the aggressive optimizeDeps configuration when running in Vitest (process.env.VITEST === 'true').
By disabling this enforced optimization during tests:
- Vitest is free to manage dependency resolution via its own defaults.
- Both workspace code and external dependencies resolve to the same native
node_modules/react. - The React instances match, and tests pass.
Verification
I verified this fix in a pnpm monorepo using set to hoist: false (strict isolation) and vitest.
-
Before: Component tests failed with
TypeError: Cannot read properties of null (reading 'useState'). - After: Tests pass successfully with no configuration workarounds needed in the consuming app.
Summary by CodeRabbit
-
Tests
- Updated dependency pre-bundling configuration for Vitest test environments. The system now conditionally skips pre-bundling optimization when running tests, improving test execution efficiency and dependency resolution behavior. This enhances test environment handling while preserving existing configuration logic for client and server environments outside of test scenarios.
βοΈ Tip: You can customize this high-level summary in your review settings.
Walkthrough
Adds a Vitest-aware guard condition to the Vite plugin's optimizeDeps configuration in packages/react-start/src/plugin/vite.ts. When running under Vitest, optimizeDeps is conditionally skipped while preserving existing client/server-based logic for non-test environments.
Changes
| Cohort / File(s) | Summary |
|---|---|
Vite plugin configuration packages/react-start/src/plugin/vite.ts |
Added Vitest-aware guard to conditionally disable optimizeDeps when VITEST environment variable is 'true' |
Estimated code review effort
π― 1 (Trivial) | β±οΈ ~3 minutes
Possibly related PRs
- TanStack/router#5650: Modifies the same optimizeDeps logic in the Vite plugin, adjusting server-side exclude list configuration
- TanStack/router#5726: Adjusts optimizeDeps include list for react-form/react-store packages in the same Vite plugin file
Suggested labels
package: react-start
Suggested reviewers
- schiller-manuel
Poem
π° A Vitest guard hops into place,
Skipping deps with grace and pace,
Tests run swift when bundling's bent,
Conditional logic, time well spent!
β¨
Pre-merge checks and finishing touches
β Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | β οΈ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
β Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | β Passed | Check skipped - CodeRabbitβs high-level summary is enabled. |
| Title check | β Passed | The title accurately describes the main change: adding a Vitest-aware condition to skip optimizeDeps configuration, which directly addresses the PR's core objective of preventing dual React instances in Vitest environments. |
β¨ Finishing touches
- [ ] π Generate docstrings
π§ͺ Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
View your CI Pipeline Execution β for commit b025a578e6b18424367eee1db7b0ad9cdc8b40a8
| Command | Status | Duration | Result |
|---|---|---|---|
nx affected --targets=test:eslint,test:unit,tes... |
β Succeeded | 5m 59s | View β |
nx run-many --target=build --exclude=examples/*... |
β Succeeded | 11s | View β |
βοΈ Nx Cloud last updated this comment at 2025-12-12 02:42:40 UTC
More templates
- tanstack-router-solid-example-authenticated-routes
- tanstack-router-solid-example-authenticated-routes-firebase
- tanstack-router-solid-example-basic
- tanstack-router-solid-example-basic-default-search-params
- tanstack-router-solid-example-basic-devtools-panel
- tanstack-router-solid-example-basic-file-based
- tanstack-router-solid-example-basic-non-nested-devtools
- tanstack-router-solid-example-basic-solid-query
- tanstack-router-solid-example-basic-solid-query-file-based
- tanstack-router-solid-example-basic-ssr-file-based
- tanstack-router-solid-example-basic-ssr-streaming-file-based
- tanstack-router-solid-example-basic-virtual-file-based
- tanstack-router-solid-example-basic-virtual-inside-file-based
- tanstack-router-solid-example-deferred-data
- tanstack-router-solid-i18n-paraglide
- tanstack-router-solid-example-kitchen-sink
- tanstack-router-solid-example-kitchen-sink-file-based
- tanstack-router-solid-example-kitchen-sink-solid-query
- tanstack-router-solid-example-kitchen-sink-solid-query-file-based
- tanstack-router-solid-example-large-file-based
- tanstack-router-solid-example-location-masking
- tanstack-router-solid-example-navigation-blocking
- tanstack-router-solid-example-quickstart
- tanstack-router-solid-example-quickstart-esbuild-file-based
- tanstack-router-solid-example-quickstart-file-based
- tanstack-router-solid-example-quickstart-rspack-file-based
- tanstack-router-solid-example-quickstart-webpack-file-based
- @tanstack/router-solid-mono-simple
- router-solid-mono-simple-lazy
- router-solid-monorepo-solid-query
- tanstack-router-solid-example-scroll-restoration
- tanstack-solid-router-search-validator-adapters
- tanstack-solid-start-example-basic
- tanstack-solid-start-example-basic-auth
- tanstack-solid-start-example-basic-authjs
- tanstack-solid-start-example-basic-cloudflare
- tanstack-solid-start-example-basic-netlify
- tanstack-solid-start-example-basic-nitro
- tanstack-start-example-basic-solid-query
- tanstack-solid-start-example-basic-static
- tanstack-solid-start-bun-hosting
- tanstack-solid-start-example-convex-better-auth
- tanstack-solid-start-example-counter
- tanstack-solid-start-i18n-paraglide
- tanstack-solid-start-example-large
- tanstack-solid-start-streaming-data-from-server-functions
- tanstack-solid-start-example-supabase-basic
- tanstack-solid-start-tailwind-v4
- tanstack-router-solid-example-view-transitions
- tanstack-router-solid-example-with-framer-motion
- tanstack-router-solid-example-with-trpc
- tanstack-router-react-example-authenticated-routes
- tanstack-router-react-example-authenticated-routes-firebase
- tanstack-router-react-example-basic
- tanstack-router-react-example-basic-default-search-params
- tanstack-router-react-example-basic-devtools-panel
- tanstack-router-react-example-basic-file-based
- tanstack-router-react-example-basic-non-nested-devtools
- tanstack-router-react-example-react-query
- tanstack-router-react-example-basic-react-query-file-based
- tanstack-router-react-example-basic-ssr-file-based
- tanstack-router-react-example-basic-ssr-streaming-file-based
- tanstack-router-react-example-basic-virtual-file-based
- tanstack-router-react-example-basic-virtual-inside-file-based
- tanstack-router-react-example-deferred-data
- tanstack-router-i18n-paraglide
- tanstack-router-react-example-kitchen-sink
- tanstack-router-react-example-kitchen-sink-file-based
- tanstack-router-react-example-kitchen-sink-react-query
- tanstack-router-react-example-kitchen-sink-react-query-file-based
- tanstack-router-react-example-large-file-based
- tanstack-router-react-example-location-masking
- tanstack-router-react-example-navigation-blocking
- tanstack-router-react-example-quickstart
- tanstack-router-react-example-quickstart-esbuild-file-based
- tanstack-router-react-example-quickstart-file-based
- tanstack-router-react-example-quickstart-rspack-file-based
- tanstack-router-react-example-quickstart-webpack-file-based
- router-monorepo-react-query
- router-mono-simple
- router-mono-simple-lazy
- tanstack-router-react-example-scroll-restoration
- tanstack-search-validator-adapters
- tanstack-start-example-bare
- tanstack-start-example-basic
- tanstack-start-example-basic-auth
- tanstack-router-react-example-basic-authjs
- tanstack-start-example-basic-cloudflare
- tanstack-start-example-basic-react-query
- tanstack-start-example-basic-rsc
- tanstack-start-example-basic-static
- tanstack-start-bun-hosting
- tanstack-start-example-clerk-basic
- tanstack-start-example-convex-trellaux
- tanstack-start-example-counter
- tanstack-start-i18n-paraglide
- tanstack-start-example-large
- tanstack-start-example-material-ui
- tanstack-start-streaming-data-from-server-functions
- tanstack-start-example-supabase-basic
- tanstack-start-tailwind-v4
- tanstack-start-example-trellaux
- tanstack-start-example-workos
- tanstack-router-react-example-view-transitions
- tanstack-router-react-example-with-framer-motion
- tanstack-router-react-example-with-trpc
- tanstack-router-react-example-with-trpc-react-query
- tanstack-router-vue-example-basic-jsx
- tanstack-router-vue-example-basic-file-based-jsx
- tanstack-router-vue-example-basic-file-based-sfc
@tanstack/arktype-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@6074
@tanstack/directive-functions-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@6074
@tanstack/eslint-plugin-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@6074
@tanstack/history
npm i https://pkg.pr.new/TanStack/router/@tanstack/history@6074
@tanstack/nitro-v2-vite-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@6074
@tanstack/react-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@6074
@tanstack/react-router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@6074
@tanstack/react-router-ssr-query
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@6074
@tanstack/react-start
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@6074
@tanstack/react-start-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@6074
@tanstack/react-start-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@6074
@tanstack/router-cli
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@6074
@tanstack/router-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@6074
@tanstack/router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@6074
@tanstack/router-devtools-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@6074
@tanstack/router-generator
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@6074
@tanstack/router-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@6074
@tanstack/router-ssr-query-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@6074
@tanstack/router-utils
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@6074
@tanstack/router-vite-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@6074
@tanstack/server-functions-plugin
npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@6074
@tanstack/solid-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@6074
@tanstack/solid-router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@6074
@tanstack/solid-router-ssr-query
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@6074
@tanstack/solid-start
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@6074
@tanstack/solid-start-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@6074
@tanstack/solid-start-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@6074
@tanstack/start-client-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@6074
@tanstack/start-plugin-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@6074
@tanstack/start-server-core
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@6074
@tanstack/start-static-server-functions
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@6074
@tanstack/start-storage-context
npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@6074
@tanstack/valibot-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@6074
@tanstack/virtual-file-routes
npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@6074
@tanstack/vue-router
npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router@6074
@tanstack/vue-router-devtools
npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-devtools@6074
@tanstack/vue-router-ssr-query
npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-ssr-query@6074
@tanstack/vue-start
npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6074
@tanstack/vue-start-client
npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-client@6074
@tanstack/vue-start-server
npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-server@6074
@tanstack/zod-adapter
npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@6074
commit: b025a57