Skip to content

feat(bundled-dev): client-side HMR#22883

Merged
h-a-n-a merged 13 commits into
renovate/rolldown-related-dependenciesfrom
feat/client-side-hmr
Jul 21, 2026
Merged

feat(bundled-dev): client-side HMR#22883
h-a-n-a merged 13 commits into
renovate/rolldown-related-dependenciesfrom
feat/client-side-hmr

Conversation

@h-a-n-a

@h-a-n-a h-a-n-a commented Jul 7, 2026

Copy link
Copy Markdown
Member

This PR moves HMR decision-making for full bundle mode (experimental.bundledDev) from the server to the browser.

Before, the browser reported every executed module to the server (vite:module-loaded), and the server computed the HMR boundaries from that copy of the client state. Now the server only reports what changed. The browser computes the boundaries itself from its own runtime state, fetches the patch, and applies it. import.meta.hot.invalidate() also stays fully in the browser.

For full details, please refer to rolldown/rolldown#10164 (comment)

Changes

Client

  • New FbmHMRClient (fbmHmrClient.ts). It receives the new fbm-update payload (changedIds + patch url + seq), computes boundaries by bubbling from each changed module through the runtime importer graph, imports the patch, and re-runs the accepted modules. All full-reload decisions (no boundary, circular chain, accept that never executed, missing factory, failed patch import) are made here.
  • Updates go through an apply queue, one at a time. A gap in seq means a lost patch, which triggers a full reload.
  • import.meta.hot.invalidate() is handled fully client-side as a re-walk from the invalidator's importers. No server request; invalidateModule is removed from the server.
  • The full-bundle-mode client lives in its own entry, dist/client/fbmClient.mjs (new rolldown config entry). client.mjs no longer bundles any full-bundle-mode code, and getHmrImplementation inlines the new entry instead.

Server

  • vite:module-loaded (per-module reporting) is replaced by vite:client-connected (clientId only). The server no longer tracks the client's executed modules. On connect, if the current output is stale, the server tells only that client to reload.
  • A patch or lazy chunk is marked delivered when its HTTP response finishes (markPayloadDelivereddevEngine.notifyPayloadDelivered). Only delivered payloads are recorded on the per-client ship map, so a later chunk may omit a module only if the chunk carrying it actually reached the client.
  • The full reload after the initial build is now sent only if a fallback page was actually served while the build ran (servedFallbackDuringInitialBuild).

@h-a-n-a
h-a-n-a force-pushed the feat/client-side-hmr branch 3 times, most recently from 07698a3 to f5d4fa6 Compare July 9, 2026 09:23
@h-a-n-a
h-a-n-a force-pushed the feat/client-side-hmr branch 4 times, most recently from 7e87bd5 to 45221f4 Compare July 16, 2026 05:56
@h-a-n-a
h-a-n-a changed the base branch from main to renovate/rolldown-related-dependencies July 17, 2026 12:26
@h-a-n-a
h-a-n-a marked this pull request as ready for review July 20, 2026 03:09
@h-a-n-a
h-a-n-a requested a review from sapphi-red July 20, 2026 03:10
@h-a-n-a
h-a-n-a force-pushed the feat/client-side-hmr branch from 65e280d to 3082b1b Compare July 21, 2026 03:38
@h-a-n-a
h-a-n-a force-pushed the renovate/rolldown-related-dependencies branch from 0842e6d to cac1cfb Compare July 21, 2026 03:49
@h-a-n-a
h-a-n-a force-pushed the feat/client-side-hmr branch from 3082b1b to d4ba516 Compare July 21, 2026 03:49
@sapphi-red sapphi-red added p3-significant High priority enhancement (priority) feat: bundled-dev labels Jul 21, 2026
@sapphi-red sapphi-red added this to the 8.2 milestone Jul 21, 2026
Comment thread packages/vite/src/module-runner/hmrHandler.ts Outdated
Comment thread packages/vite/src/node/server/middlewares/indexHtml.ts Outdated
Comment thread packages/vite/src/node/server/bundledDev.ts
Comment thread packages/vite/src/node/config.ts Outdated
@nihgwu

nihgwu commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Thanks for working on this. I’m adding bundled-dev support to RSC in vitejs/vite-plugin-react#1297, and there is one plugin-facing lifecycle gap we cannot handle safely.

The RSC plugin needs to track reachable server modules through a virtual client-reference input using addWatchFile. When that graph changes, it needs a conservative full client rebuild followed by a reload—but only after the new output has been committed.

The current APIs do not provide a safe point for this:

  • watchChange runs before regenerated output is ready.
  • Plugin hotUpdate hooks are skipped in bundled-dev mode.
  • generateBundle is pre-commit and is not called for ordinary HMR patches.
  • triggerBundleRegenerationIfStale() only works once stale state is observable and returns before regeneration, output commit, and reload complete.

Could bundled dev expose a small atomic operation, conceptually:

await environment.bundledDev.requestFullRebuild({ reload: true })

The desired contract would be:

  • safe to call from watchChange;
  • force a full build and virtual-input re-evaluation;
  • coalesce concurrent requests;
  • resolve only after memoryFiles contains the committed output;
  • send exactly one full reload when requested;
  • reject when the rebuild fails.

Vite already owns the necessary internal sequencing, so exposing this orchestration point would let plugins avoid timers, polling, direct memoryFiles access, or reimplementing bundled-dev state.

Would this fit within this PR, or would you prefer a focused follow-up in Vite core? I’d be happy to validate the API against the RSC integration.

@sapphi-red

Copy link
Copy Markdown
Member

@nihgwu Please make an issue with a smaller reproduction so that I can understand the problem. That said, hotUpdate hook might be added later so you might not need to raise it.

@h-a-n-a

h-a-n-a commented Jul 21, 2026

Copy link
Copy Markdown
Member Author

Thanks for spending the time review this long PR!

@h-a-n-a
h-a-n-a merged commit 9fd6826 into renovate/rolldown-related-dependencies Jul 21, 2026
25 checks passed
@h-a-n-a
h-a-n-a deleted the feat/client-side-hmr branch July 21, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat: bundled-dev p3-significant High priority enhancement (priority)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants