Skip to content

TanStack Start (RSC): route component does not HMR when its file has a co-located createServerFn #7618

Description

@sreetamdas

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

https://github.com/sreetamdas/tanstack-rsc-hmr-co-located-serverfn-repro

Steps to Reproduce the Bug

  1. pnpm install && pnpm dev and open http://localhost:3000.
  2. Click Increment once (so Count: 1) to seed client state.
  3. In src/routes/index.tsx, edit the <h1 data-testid="marker"> text (edit-me-baseline → anything) and save.
  4. Observe: the heading does not update; the terminal logs only (rsc) hmr update …?tss-serverfn-split; no full reload.
  5. For contrast: move getServerData into 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-rsc 0.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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions