mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[GH-ISSUE #786] Dev: RSC HMR updates modules but workerd serves stale module evaluation results #171
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#171
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @davelindo on GitHub (Apr 7, 2026).
Original GitHub issue: https://github.com/cloudflare/vinext/issues/786
Summary
RSC HMR in dev mode does not reflect file changes. After the first edit post-server-start, subsequent edits are detected by Vite but the dev server continues to serve stale rendered output. A full server restart is required to see changes.
This contradicts the documented behavior in
app-rsc-entry.js: "ISR cache is disabled in dev mode — every request re-renders fresh, matching Next.js dev behavior."Root cause
The issue is in Vite's
ModuleRunner(running inside the workerd Durable Object__VITE_RUNNER_OBJECT__via@cloudflare/vite-plugin), not in vinext's ISR page cache (which is correctly gated byprocess.env.NODE_ENV === "production").When a source file changes:
(ssr) page reloadand(rsc) hmr updatevirtual:vinext-rsc-entry) is re-evaluated viaimport.meta.hot.accept()ModuleRunner.cachedRequest()(line ~1100 ofmodule-runner.js) checksmod.evaluated && mod.promiseand returns cached evaluation results for transitive dependencies (page components, data files) without re-evaluating themjs-updateHMR path only invalidates the specific changed module and its self-accepting boundary — transitive imports through the module graph are not invalidatedThe first edit after server start works because it triggers
[vite] program reload→runner.evaluatedModules.clear()(full cache clear). Subsequent edits only trigger[vite] hot updated→js-update(partial invalidation that misses transitive deps).Evidence
Compile timestamps decrease after HMR —
performance.now()values go backwards on subsequent requests, confirming stale module evaluations are being served:ISR cache eliminated as cause —
readAppPageCacheResponsein the generated RSC entry is gated byprocess.env.NODE_ENV === "production"(line ~2059). AllisrGetcalls are within this guard. TheNoOpCacheHandlerviainstrumentation.tswas also tested and did not resolve the issue, confirming the ISR cache is not involved.Affects all RSC routes — tested on landing page routes, homepage, and solution pages. The issue is not route-specific.
Reproduction
vinext devwith@cloudflare/vite-plugin(workerd RSC environment)Potential fix direction
The RSC entry's
import.meta.hot.accept()handler (set up by@cloudflare/vite-pluginat line ~17765 ofindex.mjs) could callrunner.evaluatedModules.clear()on update to force full re-evaluation of all transitive dependencies, matching the behavior of thefull-reloadpath. This would trade some HMR performance for correctness in dev mode.Environment