Which project does this relate to?
Start / Router
Describe the bug
A route component function named component (lowercase) is runtime-valid, but it silently fails React Fast Refresh/HMR when used as the route component option with TanStack Start + Vite route splitting.
Vite reports a successful HMR update, the updated split module is fetched, and there is no warning or full reload, but the DOM stays stale until a manual browser reload. Renaming the same component to a PascalCase function fixes the issue immediately.
This is a DX footgun because the code is valid and the dev server says it updated, but the UI does not change.
Minimal failing route
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({ component })
function component() {
return <div>111</div>
}
Steps:
- Run the dev server.
- Open the route in the browser.
- Change
111 to 112 and save.
- Observe that Vite logs a successful HMR update for the route module and the split component module.
- The browser DOM still shows
111.
- Manual reload shows
112.
During local debugging, the Vite websocket delivered a js-update for /src/routes/index.tsx, the browser fetched /src/routes/index.tsx?...&tsr-split=component, and that split module contained the new JSX text. The DOM still did not update.
Working version
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/')({ component: Home })
function Home() {
return <div>112</div>
}
With the PascalCase function name, the transformed split module registers the component for React Refresh, e.g. it contains a $RefreshReg$ call for Home, and HMR updates the DOM correctly.
The same naming rule also matters for root/shell components. This works:
export const Route = createRootRoute({
shellComponent: RootComponent,
})
function RootComponent() {
return <Outlet />
}
Expected behavior
One of these would avoid the silent stale UI state:
- warn when a route component option points at a lowercase function/component identifier
- fallback to a full reload when React Refresh cannot register the split route component
- generate/hoist a PascalCase wrapper for the split component
- document this as a route component requirement
Actual behavior
HMR appears to succeed, but the rendered route remains stale until manual reload.
Platform
Local reproduction:
@tanstack/react-router: 1.170.17
@tanstack/react-start: 1.168.27
@tanstack/router-cli: 1.167.18
@vitejs/plugin-react: 6.0.3
vite: 8.1.3
react: 19.2.7
react-dom: 19.2.7
@cloudflare/vite-plugin: 1.43.0
- Node:
26.0.0
- Bun:
1.3.14
- OS: macOS
- Browser: Chrome / in-app Chromium
Vite plugin order:
plugins: [
cloudflare({ viteEnvironment: { name: 'ssr' } }),
tailwindcss(),
tanstackStart({ router: { generatedRouteTree: 'routes.generated.ts' } }),
viteReact(),
]
Related issues / PRs
This looks related to prior React Refresh/HMR component-shape fixes, but I could not find an exact report for a lowercase named route component silently failing:
Which project does this relate to?
Start / Router
Describe the bug
A route component function named
component(lowercase) is runtime-valid, but it silently fails React Fast Refresh/HMR when used as the routecomponentoption with TanStack Start + Vite route splitting.Vite reports a successful HMR update, the updated split module is fetched, and there is no warning or full reload, but the DOM stays stale until a manual browser reload. Renaming the same component to a PascalCase function fixes the issue immediately.
This is a DX footgun because the code is valid and the dev server says it updated, but the UI does not change.
Minimal failing route
Steps:
111to112and save.111.112.During local debugging, the Vite websocket delivered a
js-updatefor/src/routes/index.tsx, the browser fetched/src/routes/index.tsx?...&tsr-split=component, and that split module contained the new JSX text. The DOM still did not update.Working version
With the PascalCase function name, the transformed split module registers the component for React Refresh, e.g. it contains a
$RefreshReg$call forHome, and HMR updates the DOM correctly.The same naming rule also matters for root/shell components. This works:
Expected behavior
One of these would avoid the silent stale UI state:
Actual behavior
HMR appears to succeed, but the rendered route remains stale until manual reload.
Platform
Local reproduction:
@tanstack/react-router:1.170.17@tanstack/react-start:1.168.27@tanstack/router-cli:1.167.18@vitejs/plugin-react:6.0.3vite:8.1.3react:19.2.7react-dom:19.2.7@cloudflare/vite-plugin:1.43.026.0.01.3.14Vite plugin order:
Related issues / PRs
This looks related to prior React Refresh/HMR component-shape fixes, but I could not find an exact report for a lowercase named route component silently failing:
createServerFnissue.