feat(bundled-dev): client-side HMR#22883
Conversation
07698a3 to
f5d4fa6
Compare
7e87bd5 to
45221f4
Compare
65e280d to
3082b1b
Compare
0842e6d to
cac1cfb
Compare
3082b1b to
d4ba516
Compare
|
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 The current APIs do not provide a safe point for this:
Could bundled dev expose a small atomic operation, conceptually: await environment.bundledDev.requestFullRebuild({ reload: true })The desired contract would be:
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. |
|
@nihgwu Please make an issue with a smaller reproduction so that I can understand the problem. That said, |
…lename uniqueness
…he option comment"
|
Thanks for spending the time review this long PR! |
9fd6826
into
renovate/rolldown-related-dependencies
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
FbmHMRClient(fbmHmrClient.ts). It receives the newfbm-updatepayload (changedIds+ patchurl+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.seqmeans 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;invalidateModuleis removed from the server.dist/client/fbmClient.mjs(new rolldown config entry).client.mjsno longer bundles any full-bundle-mode code, andgetHmrImplementationinlines the new entry instead.Server
vite:module-loaded(per-module reporting) is replaced byvite: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.markPayloadDelivered→devEngine.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.servedFallbackDuringInitialBuild).