UNPKG

next

Version:

The React Framework

125 lines (123 loc) 5.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "TurbopackHmr", { enumerable: true, get: function() { return TurbopackHmr; } }); const _deferredemit = require("../../../shared/lib/turbopack/deferred-emit"); // 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; // 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 the `[Fast Refresh] rebuilding` message by // 100ms. If we get a BUILT event within that threshold and nothing has // changed, just suppress the message entirely. (The dev server applies the // same defer to the BUILDING HMR message itself; see `DeferredEmit` usage in // hot-reloader-turbopack.ts.) #deferredReportHmrStart; #reportedHmrStart; constructor(){ this.#updatedModules = new Set(); this.#deferredReportHmrStart = new _deferredemit.DeferredEmit(); this.#reportedHmrStart = false; } onBuilding() { this.#lastUpdateMsSinceEpoch = undefined; this.#deferredReportHmrStart.cancel(); this.#startMsSinceEpoch = Date.now(); // report the HMR start after a short delay this.#deferredReportHmrStart.schedule(// 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, ()=>{ console.log('[Fast Refresh] rebuilding'); this.#reportedHmrStart = true; }); } /** Helper for other `onEvent` methods. */ #onUpdate() { this.#deferredReportHmrStart.flush(); 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.#deferredReportHmrStart.cancel(); return null; } this.#deferredReportHmrStart.flush(); 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){ if (!mergedUpdate.entries) continue; 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