Repository navigation
Description
Which project does this relate to?
Start
Describe the bug
In RSC mode, a route component does not Hot Module Reload when its route file also contains a co-located createServerFn (e.g. a loader server function in the same file as the route component).
On editing the route component's JSX, the terminal shows only:
(rsc) hmr update /src/routes/index.tsx?tss-serverfn-split
…with no client update, so the DOM never changes — and there is no full reload either. Moving the createServerFn into a separate file restores Fast Refresh, which is the tell that this is specifically about co-location.
I've traced the root cause to @vitejs/plugin-rsc and opened a proposed fix upstream: vitejs/vite-plugin-react#1248. Filing here for visibility/tracking (so Start users hitting "my route won't HMR" find the cause + workaround, and so the @vitejs/plugin-rsc bump is tracked once it lands).
Root cause (short version): the route file's createServerFn puts the file in the rsc module graph. @vitejs/plugin-rsc's client hotUpdate returns [] for any file in the rsc graph that isn't inside a "use client" boundary (a guard to avoid full reloads from server-only files watched as style deps, e.g. Tailwind/addWatchFile). The route component is a genuine client module (imported by the client route tree) but isn't a "use client" reference, so its client HMR is wrongly suppressed.
Workaround: move the createServerFn/server code into a separate (e.g. *.server.ts) module and import it into the route file.
Complete minimal reproducer
Steps to Reproduce the Bug
pnpm install && pnpm devand open http://localhost:3000.- Click Increment once (so
Count: 1) to seed client state. - In
src/routes/index.tsx, edit the<h1 data-testid="marker">text (edit-me-baseline→ anything) and save. - Observe: the heading does not update; the terminal logs only
(rsc) hmr update …?tss-serverfn-split; no full reload. - For contrast: move
getServerDatainto a separate file and import it — HMR now works (heading updates, counter preserved).
Expected behavior
Editing a route component's JSX should Fast Refresh the component in dev, regardless of whether the route file also defines a createServerFn. Server-only code co-located in the file should not strip the route component's client HMR boundary.
Platform
- Router / Start Version:
@tanstack/react-start^1.168.25,@tanstack/react-router^1.170.15 - OS: macOS
- Browser: Chrome
- Bundler: vite ^8
- Bundler plugin:
@vitejs/plugin-rsc0.5.27
Additional context
Proposed upstream fix (with full analysis): vitejs/vite-plugin-react#1248 — only suppress the client HMR when the file has no non-CSS client importers (mirroring the existing rsc-branch's importers.every(isCSSRequest) check), so genuine client modules co-located with rsc-graph code keep Fast Refresh.
Activity
sreetamdas commentedon Jul 25, 2026
Resolved upstream — this is fixed as of
@vitejs/[email protected].If you landed here because a Start route won't hot-reload: update
@vitejs/plugin-rscto>=0.5.30and the co-locatedcreateServerFnworkaround (moving server code into a separate file) is no longer needed.What was wrong: a route file containing a
createServerFnis present in therscmodule graph.@vitejs/plugin-rsc's clienthotUpdatehook returned[]for any file in that graph which wasn't inside a"use client"boundary — a guard that exists to stop server-only files watched as style deps (Tailwind,addWatchFile) from triggering full reloads. A genuine client route component co-located with a server fn is in the rsc graph but is not a"use client"reference, so its client HMR was suppressed along with it. The symptom was an(rsc) hmr update …?tss-serverfn-splitin the terminal with no client update, so the DOM never changed and there was no full reload either.The fix: vitejs/vite-plugin-react#1248 narrows the guard — CSS importers are still reloaded, but it only bails out when the changed module has no non-CSS client importer. So genuine client modules co-located with rsc-graph code keep Fast Refresh, while the original Tailwind/style-dep behaviour is preserved.
Verified against the reproducer linked in the issue:
0.5.270.5.30(rsc) hmr update …?tss-serverfn-splitonly(client) hmr update /src/routes/index.tsx, …?tsr-split=component+ the rsc lineAlso checked that a co-located route importing a CSS module still Fast Refreshes, and that a CSS-only edit still hot-swaps styles without a full reload, so the behaviour the original guard protected is intact.
Closing — the remaining piece is raising Start's
@vitejs/plugin-rscfloor past the affected range, opened as #7900.