"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "TurbopackHmr", { enumerable: true, get: function() { return TurbopackHmr; } }); // How long to wait before reporting the HMR start, used to suppress irrelevant // `BUILDING` events. Does not impact reported latency. const TURBOPACK_HMR_START_DELAY_MS = 100; class TurbopackHmr { #updatedModules; #startMsSinceEpoch; #lastUpdateMsSinceEpoch; #deferredReportHmrStartId; #reportedHmrStart; constructor(){ this.#updatedModules = new Set(); this.#reportedHmrStart = false; } // HACK: Turbopack tends to generate a lot of irrelevant "BUILDING" actions, // as it reports *any* compilation, including fully no-op/cached compilations // and those unrelated to HMR. Fixing this would require significant // architectural changes. // // Work around this by deferring any "rebuilding" message by 100ms. If we get // a BUILT event within that threshold and nothing has changed, just suppress // the message entirely. #runDeferredReportHmrStart() { if (this.#deferredReportHmrStartId != null) { console.log('[Fast Refresh] rebuilding'); this.#reportedHmrStart = true; this.#cancelDeferredReportHmrStart(); } } #cancelDeferredReportHmrStart() { clearTimeout(this.#deferredReportHmrStartId); this.#deferredReportHmrStartId = undefined; } onBuilding() { this.#lastUpdateMsSinceEpoch = undefined; this.#cancelDeferredReportHmrStart(); this.#startMsSinceEpoch = Date.now(); // report the HMR start after a short delay this.#deferredReportHmrStartId = setTimeout(()=>this.#runDeferredReportHmrStart(), // debugging feature: don't defer/suppress noisy no-op HMR update messages self.__NEXT_HMR_TURBOPACK_REPORT_NOISY_NOOP_EVENTS ? 0 : TURBOPACK_HMR_START_DELAY_MS); } /** Helper for other `onEvent` methods. */ #onUpdate() { this.#runDeferredReportHmrStart(); this.#lastUpdateMsSinceEpoch = Date.now(); } onTurbopackMessage(msg) { this.#onUpdate(); const updatedModules = extractModulesFromTurbopackMessage(msg.data); for (const module of updatedModules){ this.#updatedModules.add(module); } } onServerComponentChanges() { this.#onUpdate(); } onReloadPage() { this.#onUpdate(); } onPageAddRemove() { this.#onUpdate(); } /** * @returns `null` if the caller should ignore the update entirely. Returns an * object with `hasUpdates: false` if the caller should report the end of * the HMR in the browser console, but the HMR was a no-op. */ onBuilt() { // Check that we got *any* `TurbopackMessage`, even if // `updatedModules` is empty (not everything gets recorded there). // // There's also a case where `onBuilt` gets called before `onBuilding`, // which can happen during initial page load. Ignore that too! const hasUpdates = this.#lastUpdateMsSinceEpoch != null && this.#startMsSinceEpoch != null; if (!hasUpdates && !this.#reportedHmrStart) { // suppress the update entirely this.#cancelDeferredReportHmrStart(); return null; } this.#runDeferredReportHmrStart(); const result = { hasUpdates, updatedModules: this.#updatedModules, startMsSinceEpoch: this.#startMsSinceEpoch, endMsSinceEpoch: this.#lastUpdateMsSinceEpoch ?? Date.now() }; this.#updatedModules = new Set(); this.#reportedHmrStart = false; return result; } } function extractModulesFromTurbopackMessage(data) { const updatedModules = new Set(); const updates = Array.isArray(data) ? data : [ data ]; for (const update of updates){ // TODO this won't capture changes to CSS since they don't result in a "merged" update if (update.type !== 'partial' || update.instruction.type !== 'ChunkListUpdate' || update.instruction.merged === undefined) { continue; } for (const mergedUpdate of update.instruction.merged){ for (const name of Object.keys(mergedUpdate.entries)){ const res = /(.*)\s+[([].*/.exec(name); if (res === null) { continue; } updatedModules.add(res[1]); } } } return updatedModules; } if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') { Object.defineProperty(exports.default, '__esModule', { value: true }); Object.assign(exports.default, exports); module.exports = exports.default; } //# sourceMappingURL=turbopack-hot-reloader-common.js.map