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

Skip to content

Commit 805a8ba

Browse files
committed
fix(turbopack): Suppress logging for short no-op turbopack HMRs
1 parent 026445d commit 805a8ba

File tree

4 files changed

+109
-15
lines changed

4 files changed

+109
-15
lines changed

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,9 @@ function processMessage(
267267
sendMessage,
268268
[...hmrUpdate.updatedModules],
269269
hmrUpdate.startMsSinceEpoch,
270-
hmrUpdate.endMsSinceEpoch
270+
hmrUpdate.endMsSinceEpoch,
271+
// suppress the `client-hmr-latency` event if the update was a no-op:
272+
hmrUpdate.hasUpdates
271273
)
272274
}
273275
dispatcher.onBuildOk()
@@ -301,8 +303,8 @@ function processMessage(
301303
} else {
302304
webpackStartMsSinceEpoch = Date.now()
303305
setPendingHotUpdateWebpack()
306+
console.log('[Fast Refresh] rebuilding')
304307
}
305-
console.log('[Fast Refresh] rebuilding')
306308
break
307309
}
308310
case HMR_ACTIONS_SENT_TO_BROWSER.BUILT:
@@ -385,21 +387,22 @@ function processMessage(
385387
break
386388
}
387389
case HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE: {
390+
turbopackHmr!.onTurbopackMessage(obj)
388391
dispatcher.onBeforeRefresh()
389392
processTurbopackMessage({
390393
type: HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE,
391394
data: obj.data,
392395
})
393-
dispatcher.onRefresh()
394396
if (RuntimeErrorHandler.hadRuntimeError) {
395397
console.warn(REACT_REFRESH_FULL_RELOAD_FROM_ERROR)
396398
performFullReload(null, sendMessage)
397399
}
398-
turbopackHmr!.onTurbopackMessage(obj)
400+
dispatcher.onRefresh()
399401
break
400402
}
401403
// TODO-APP: make server component change more granular
402404
case HMR_ACTIONS_SENT_TO_BROWSER.SERVER_COMPONENT_CHANGES: {
405+
turbopackHmr?.onServerComponentChanges()
403406
sendMessage(
404407
JSON.stringify({
405408
event: 'server-component-reload-page',
@@ -433,6 +436,7 @@ function processMessage(
433436
return
434437
}
435438
case HMR_ACTIONS_SENT_TO_BROWSER.RELOAD_PAGE: {
439+
turbopackHmr?.onReloadPage()
436440
sendMessage(
437441
JSON.stringify({
438442
event: 'client-reload-page',
@@ -445,6 +449,7 @@ function processMessage(
445449
}
446450
case HMR_ACTIONS_SENT_TO_BROWSER.ADDED_PAGE:
447451
case HMR_ACTIONS_SENT_TO_BROWSER.REMOVED_PAGE: {
452+
turbopackHmr?.onPageAddRemove()
448453
// TODO-APP: potentially only refresh if the currently viewed page was added/removed.
449454
return router.hmrRefresh()
450455
}

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

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ function handleSuccess() {
138138
sendMessage,
139139
[...hmrUpdate.updatedModules],
140140
hmrUpdate.startMsSinceEpoch,
141-
hmrUpdate.endMsSinceEpoch
141+
hmrUpdate.endMsSinceEpoch,
142+
hmrUpdate.hasUpdates
142143
)
143144
}
144145
onBuildOk()
@@ -275,8 +276,8 @@ function processMessage(obj: HMR_ACTION_TYPES) {
275276
turbopackHmr!.onBuilding()
276277
} else {
277278
webpackStartMsSinceEpoch = Date.now()
279+
console.log('[Fast Refresh] rebuilding')
278280
}
279-
console.log('[Fast Refresh] rebuilding')
280281
break
281282
}
282283
case HMR_ACTIONS_SENT_TO_BROWSER.BUILT:
@@ -323,6 +324,7 @@ function processMessage(obj: HMR_ACTION_TYPES) {
323324
return handleSuccess()
324325
}
325326
case HMR_ACTIONS_SENT_TO_BROWSER.SERVER_COMPONENT_CHANGES: {
327+
turbopackHmr?.onServerComponentChanges()
326328
if (hasCompileErrors || RuntimeErrorHandler.hadRuntimeError) {
327329
window.location.reload()
328330
}
@@ -348,6 +350,7 @@ function processMessage(obj: HMR_ACTION_TYPES) {
348350
break
349351
}
350352
case HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE: {
353+
turbopackHmr!.onTurbopackMessage(obj)
351354
onBeforeRefresh()
352355
for (const listener of turbopackMessageListeners) {
353356
listener({
@@ -360,7 +363,6 @@ function processMessage(obj: HMR_ACTION_TYPES) {
360363
performFullReload(null)
361364
}
362365
onRefresh()
363-
turbopackHmr!.onTurbopackMessage(obj)
364366
break
365367
}
366368
default: {

packages/next/src/client/components/react-dev-overlay/utils/report-hmr-latency.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,29 @@ declare global {
44
}
55
}
66

7+
/**
8+
* Logs information about a completed HMR to the console, the server (via a
9+
* `client-hmr-latency` event), and to `self.__NEXT_HMR_LATENCY_CB` (a debugging
10+
* hook).
11+
*
12+
* @param hasUpdate Set this to `false` to avoid reporting the HMR event via a
13+
* `client-hmr-latency` event or to `self.__NEXT_HMR_LATENCY_CB`. Used by
14+
* turbopack when we must report a message to the browser console (because we
15+
* already logged a "rebuilding" message), but it's not a real HMR, so we
16+
* don't want to impact our telemetry.
17+
*/
718
export default function reportHmrLatency(
819
sendMessage: (message: string) => void,
920
updatedModules: ReadonlyArray<string | number>,
1021
startMsSinceEpoch: number,
11-
endMsSinceEpoch: number
22+
endMsSinceEpoch: number,
23+
hasUpdate: boolean = true
1224
) {
1325
const latencyMs = endMsSinceEpoch - startMsSinceEpoch
1426
console.log(`[Fast Refresh] done in ${latencyMs}ms`)
27+
if (!hasUpdate) {
28+
return
29+
}
1530
sendMessage(
1631
JSON.stringify({
1732
event: 'client-hmr-latency',

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

Lines changed: 79 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,36 +22,97 @@ 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+
// report the HMR start after a short delay
57+
this.#deferredReportHmrStartId = setTimeout(
58+
() => this.#runDeferredReportHmrStart(),
59+
// debugging feature: don't defer/suppress noisy no-op HMR update messages
60+
self.__NEXT_HMR_TURBOPACK_REPORT_NOISY_NOOP_EVENTS
61+
? 0
62+
: TURBOPACK_HMR_START_DELAY_MS
63+
)
2264
}
2365

24-
onTurbopackMessage(msg: TurbopackMessageAction) {
66+
/** Helper for other `onEvent` methods. */
67+
#onUpdate() {
68+
this.#runDeferredReportHmrStart()
2569
this.#lastUpdateMsSinceEpoch = Date.now()
70+
}
71+
72+
onTurbopackMessage(msg: TurbopackMessageAction) {
73+
this.#onUpdate()
2674
const updatedModules = extractModulesFromTurbopackMessage(msg.data)
2775
for (const module of updatedModules) {
2876
this.#updatedModules.add(module)
2977
}
3078
}
3179

80+
onServerComponentChanges() {
81+
this.#onUpdate()
82+
}
83+
84+
onReloadPage() {
85+
this.#onUpdate()
86+
}
87+
88+
onPageAddRemove() {
89+
this.#onUpdate()
90+
}
91+
92+
/**
93+
* @returns `null` if the caller should ignore the update entirely. Returns an
94+
* object with `hasUpdates: false` if the caller should report the end of
95+
* the HMR in the browser console, but the HMR was a no-op.
96+
*/
3297
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) {
98+
// Check that we got *any* `TurbopackMessageAction`, even if
99+
// `updatedModules` is empty (not everything gets recorded there).
100+
//
101+
// There's also a case where `onBuilt` gets called before `onBuilding`,
102+
// which can happen during initial page load. Ignore that too!
103+
const hasUpdates =
104+
this.#lastUpdateMsSinceEpoch != null && this.#startMsSinceEpoch != null
105+
if (!hasUpdates && this.#deferredReportHmrStartId != null) {
106+
// suppress the update entirely
107+
this.#cancelDeferredReportHmrStart()
36108
return null
37109
}
110+
this.#runDeferredReportHmrStart()
111+
38112
const result = {
113+
hasUpdates,
39114
updatedModules: this.#updatedModules,
40115
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.
44116
endMsSinceEpoch: this.#lastUpdateMsSinceEpoch ?? Date.now(),
45117
}
46118
this.#updatedModules = new Set()

0 commit comments

Comments
 (0)