You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When using two tanstackRouter() plugin instances in the same Vite config (e.g., for serving two different route trees in development), an intermittent Duplicate declaration "hot" error occurs during SSR module evaluation.
Error when evaluating SSR module ../client/src/entry-server-ai.tsx: Duplicate declaration "hot"
Plugin: tanstack-router:code-splitter:compile-reference-file
File: /path/to/routes-ai/app/tasks.tsx
Root Cause
globalThis.TSR_ROUTES_BY_ID_MAP is shared across all plugin instances and overwritten on every generator run.
Both generator instances write to the same global, so the last one to run wins. Meanwhile, both code-splitter instances register their own tanstack-router:code-splitter:compile-reference-file transform hook. Vite does not deduplicate plugins with the same name, so both transform hooks run on every matching file.
When a route file is transformed:
Code-splitter instance Issue on "/" paths #1 transforms the file, and the react-refresh-ignored-route-exports plugin injects const hot = import.meta.hot at program scope
Code-splitter instance Navigate without second parameter #2 receives the already-transformed output, sees the file in the shared TSR_ROUTES_BY_ID_MAP, transforms it again, injecting a secondconst hot = import.meta.hot at program scope
This causes the Babel Duplicate declaration "hot" error.
Start the dev server and make a few file edits to trigger HMR. The error will appear intermittently during SSR evaluation.
Expected behavior
Each tanstackRouter() instance should only transform route files from its own routesDirectory. The TSR_ROUTES_BY_ID_MAP should be namespaced per instance (e.g., keyed by routesDirectory) rather than shared globally, and each code-splitter should only process files from its own namespace.
Suggested fix
Namespace the global map — use a Map<instanceId, Map<fileId, info>> structure, or key by routesDirectory
Each code-splitter checks only its own namespace — in the transform handler, filter TSR_ROUTES_BY_ID_MAP to only files belonging to this instance's routesDirectory
How Do You Currently Work Around This?
Setting codeSplittingOptions: { addHmr: false } on both instances prevents the duplicate injection, but loses TanStack Router's custom route HMR (falls back to full page reloads).
Describe the bug
When using two
tanstackRouter()plugin instances in the same Vite config (e.g., for serving two different route trees in development), an intermittentDuplicate declaration "hot"error occurs during SSR module evaluation.Root Cause
globalThis.TSR_ROUTES_BY_ID_MAPis shared across all plugin instances and overwritten on every generator run.In
router-generator-plugin.js:Both generator instances write to the same global, so the last one to run wins. Meanwhile, both code-splitter instances register their own
tanstack-router:code-splitter:compile-reference-filetransform hook. Vite does not deduplicate plugins with the same name, so both transform hooks run on every matching file.When a route file is transformed:
react-refresh-ignored-route-exportsplugin injectsconst hot = import.meta.hotat program scopeTSR_ROUTES_BY_ID_MAP, transforms it again, injecting a secondconst hot = import.meta.hotat program scopeThis causes the Babel
Duplicate declaration "hot"error.introduced with PR #7144 (ping @schiller-manuel )
Why it's intermittent
The
TSR_ROUTES_BY_ID_MAPis overwritten on every generator run andwatchChangeevent. Depending on timing:Your minimal, reproducible example
Vite config with two
tanstackRouter()instances, which is a common pattern for serving multiple domains/route trees from one dev server:Start the dev server and make a few file edits to trigger HMR. The error will appear intermittently during SSR evaluation.
Expected behavior
Each
tanstackRouter()instance should only transform route files from its ownroutesDirectory. TheTSR_ROUTES_BY_ID_MAPshould be namespaced per instance (e.g., keyed byroutesDirectory) rather than shared globally, and each code-splitter should only process files from its own namespace.Suggested fix
Map<instanceId, Map<fileId, info>>structure, or key byroutesDirectoryTSR_ROUTES_BY_ID_MAPto only files belonging to this instance'sroutesDirectoryHow Do You Currently Work Around This?
Setting
codeSplittingOptions: { addHmr: false }on both instances prevents the duplicate injection, but loses TanStack Router's custom route HMR (falls back to full page reloads).Versions
@tanstack/router-plugin: 1.167.20@tanstack/react-router: 1.168.19vite: 8.0.8@vitejs/plugin-react: 6.0.1