Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4e6b8e0

Browse files
committed
WIP fix(turbopack): Suppress logging for short no-op turbopack HMRs
1 parent 865a903 commit 4e6b8e0

File tree

3 files changed

+64
-18
lines changed

3 files changed

+64
-18
lines changed

packages/next/src/client/components/react-dev-overlay/app/hot-reloader-client.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,8 @@ function processMessage(
289289
function handleHotUpdate() {
290290
if (process.env.TURBOPACK) {
291291
const hmrUpdate = turbopackHmr!.onBuilt()
292-
if (hmrUpdate != null) {
292+
if (hmrUpdate != null && hmrUpdate.hasUpdates) {
293+
dispatcher.onBeforeRefresh()
293294
reportHmrLatency(
294295
sendMessage,
295296
[...hmrUpdate.updatedModules],
@@ -345,8 +346,8 @@ function processMessage(
345346
} else {
346347
webpackStartMsSinceEpoch = Date.now()
347348
setPendingHotUpdateWebpack()
349+
console.log('[Fast Refresh] rebuilding')
348350
}
349-
console.log('[Fast Refresh] rebuilding')
350351
break
351352
}
352353
case HMR_ACTIONS_SENT_TO_BROWSER.BUILT:
@@ -429,7 +430,6 @@ function processMessage(
429430
break
430431
}
431432
case HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE: {
432-
dispatcher.onBeforeRefresh()
433433
processTurbopackMessage({
434434
type: HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE,
435435
data: obj.data,

packages/next/src/client/components/react-dev-overlay/pages/hot-reloader-client.ts

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,7 @@ import {
5353
} from '../shared'
5454
import { RuntimeErrorHandler } from '../../errors/runtime-error-handler'
5555
import reportHmrLatency from '../utils/report-hmr-latency'
56-
import {
57-
extractModulesFromTurbopackMessage,
58-
TurbopackHmr,
59-
} from '../utils/turbopack-hot-reloader-common'
56+
import { TurbopackHmr } from '../utils/turbopack-hot-reloader-common'
6057
// This alternative WebpackDevServer combines the functionality of:
6158
// https://github.com/webpack/webpack-dev-server/blob/webpack-1/client/index.js
6259
// https://github.com/webpack/webpack/blob/webpack-1/hot/dev-server.js
@@ -132,7 +129,7 @@ function handleSuccess() {
132129

133130
if (process.env.TURBOPACK) {
134131
const hmrUpdate = turbopackHmr!.onBuilt()
135-
if (hmrUpdate != null) {
132+
if (hmrUpdate != null && hmrUpdate.hasUpdates) {
136133
reportHmrLatency(
137134
sendMessage,
138135
[...hmrUpdate.updatedModules],
@@ -298,8 +295,8 @@ function processMessage(obj: HMR_ACTION_TYPES) {
298295
turbopackHmr!.onBuilding()
299296
} else {
300297
webpackStartMsSinceEpoch = Date.now()
298+
console.log('[Fast Refresh] rebuilding')
301299
}
302-
console.log('[Fast Refresh] rebuilding')
303300
break
304301
}
305302
case HMR_ACTIONS_SENT_TO_BROWSER.BUILT:
@@ -370,8 +367,6 @@ function processMessage(obj: HMR_ACTION_TYPES) {
370367
break
371368
}
372369
case HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE: {
373-
const updatedModules = extractModulesFromTurbopackMessage(obj.data)
374-
onBeforeFastRefresh([...updatedModules])
375370
for (const listener of turbopackMessageListeners) {
376371
listener({
377372
type: HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE,

packages/next/src/client/components/react-dev-overlay/utils/turbopack-hot-reloader-common.ts

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,18 @@
11
import type { TurbopackMessageAction } from '../../../../server/dev/hot-reloader-types'
22
import type { Update as TurbopackUpdate } from '../../../../build/swc/types'
33

4+
declare global {
5+
interface Window {
6+
__NEXT_HMR_TURBOPACK_REPORT_NOISY_NOOP_EVENTS: boolean | undefined
7+
}
8+
}
9+
10+
// How long to wait before reporting the HMR start, used to suppress irrelevant
11+
// `BUILDING` events. Does not impact reported latency.
12+
const TURBOPACK_HMR_START_DELAY_MS = 100
13+
414
interface HmrUpdate {
15+
hasUpdates: boolean
516
updatedModules: Set<string>
617
startMsSinceEpoch: number
718
endMsSinceEpoch: number
@@ -11,17 +22,51 @@ export class TurbopackHmr {
1122
#updatedModules: Set<string>
1223
#startMsSinceEpoch: number | undefined
1324
#lastUpdateMsSinceEpoch: number | undefined
25+
#deferredReportHmrStartId: ReturnType<typeof setTimeout> | undefined
1426

1527
constructor() {
1628
this.#updatedModules = new Set()
1729
}
1830

31+
// HACK: Turbopack tends to generate a lot of irrelevant "BUILDING" actions,
32+
// as it reports *any* compilation, including fully no-op/cached compilations
33+
// and those unrelated to HMR. Fixing this would require significant
34+
// architectural changes.
35+
//
36+
// Work around this by deferring any "rebuilding" message by 100ms. If we get
37+
// a BUILT event within that threshold and nothing has changed, just suppress
38+
// the message entirely.
39+
#runDeferredReportHmrStart() {
40+
if (this.#deferredReportHmrStartId != null) {
41+
console.log('[Fast Refresh] rebuilding')
42+
this.#cancelDeferredReportHmrStart()
43+
}
44+
}
45+
46+
#cancelDeferredReportHmrStart() {
47+
clearTimeout(this.#deferredReportHmrStartId)
48+
this.#deferredReportHmrStartId = undefined
49+
}
50+
1951
onBuilding() {
2052
this.#lastUpdateMsSinceEpoch = undefined
53+
this.#cancelDeferredReportHmrStart()
2154
this.#startMsSinceEpoch = Date.now()
55+
56+
if (self.__NEXT_HMR_TURBOPACK_REPORT_NOISY_NOOP_EVENTS) {
57+
// debugging feature: don't defer/suppress noisy no-op HMR update messages
58+
this.#runDeferredReportHmrStart()
59+
} else {
60+
// report the HMR start after a short delay
61+
this.#deferredReportHmrStartId = setTimeout(
62+
() => this.#runDeferredReportHmrStart(),
63+
TURBOPACK_HMR_START_DELAY_MS
64+
)
65+
}
2266
}
2367

2468
onTurbopackMessage(msg: TurbopackMessageAction) {
69+
this.#runDeferredReportHmrStart()
2570
this.#lastUpdateMsSinceEpoch = Date.now()
2671
const updatedModules = extractModulesFromTurbopackMessage(msg.data)
2772
for (const module of updatedModules) {
@@ -30,25 +75,31 @@ export class TurbopackHmr {
3075
}
3176

3277
onBuilt(): HmrUpdate | null {
33-
// it's possible for `this.#startMsSinceEpoch` to not be set if this was the initial
34-
// computation, just return null in this case.
35-
if (this.#startMsSinceEpoch == null) {
78+
// Check that we got *any* `TurbopackMessageAction`, even if `updatedModules` is empty (not
79+
// everything gets recorded there).
80+
//
81+
// This also handles for the case where `onBuilt` gets called before `onBuilding`, which can
82+
// happen during initial page load. We should ignore this.
83+
const hasUpdates = this.#lastUpdateMsSinceEpoch != null
84+
if (!hasUpdates && this.#deferredReportHmrStartId != null) {
85+
// suppress the update entirely
86+
this.#cancelDeferredReportHmrStart()
3687
return null
3788
}
89+
this.#runDeferredReportHmrStart()
90+
3891
const result = {
92+
hasUpdates,
3993
updatedModules: this.#updatedModules,
4094
startMsSinceEpoch: this.#startMsSinceEpoch!,
41-
// Turbopack has a debounce which causes every BUILT message to appear
42-
// 30ms late. We don't want to include this latency in our reporting, so
43-
// prefer to use the last TURBOPACK_MESSAGE time.
4495
endMsSinceEpoch: this.#lastUpdateMsSinceEpoch ?? Date.now(),
4596
}
4697
this.#updatedModules = new Set()
4798
return result
4899
}
49100
}
50101

51-
export function extractModulesFromTurbopackMessage(
102+
function extractModulesFromTurbopackMessage(
52103
data: TurbopackUpdate | TurbopackUpdate[]
53104
): Set<string> {
54105
const updatedModules: Set<string> = new Set()

0 commit comments

Comments
 (0)