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

Skip to content

Commit 3f53bc7

Browse files
committed
fix(turbopack): Suppress logging for short no-op turbopack HMRs
1 parent f5a3e22 commit 3f53bc7

File tree

4 files changed

+101
-15
lines changed

4 files changed

+101
-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: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ function handleSuccess() {
133133

134134
if (process.env.TURBOPACK) {
135135
const hmrUpdate = turbopackHmr!.onBuilt()
136-
if (hmrUpdate != null) {
136+
if (hmrUpdate != null && hmrUpdate.hasUpdates) {
137137
reportHmrLatency(
138138
sendMessage,
139139
[...hmrUpdate.updatedModules],
@@ -275,8 +275,8 @@ function processMessage(obj: HMR_ACTION_TYPES) {
275275
turbopackHmr!.onBuilding()
276276
} else {
277277
webpackStartMsSinceEpoch = Date.now()
278+
console.log('[Fast Refresh] rebuilding')
278279
}
279-
console.log('[Fast Refresh] rebuilding')
280280
break
281281
}
282282
case HMR_ACTIONS_SENT_TO_BROWSER.BUILT:
@@ -323,6 +323,7 @@ function processMessage(obj: HMR_ACTION_TYPES) {
323323
return handleSuccess()
324324
}
325325
case HMR_ACTIONS_SENT_TO_BROWSER.SERVER_COMPONENT_CHANGES: {
326+
turbopackHmr?.onServerComponentChanges()
326327
if (hasCompileErrors || RuntimeErrorHandler.hadRuntimeError) {
327328
window.location.reload()
328329
}
@@ -348,6 +349,7 @@ function processMessage(obj: HMR_ACTION_TYPES) {
348349
break
349350
}
350351
case HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_MESSAGE: {
352+
turbopackHmr!.onTurbopackMessage(obj)
351353
onBeforeRefresh()
352354
for (const listener of turbopackMessageListeners) {
353355
listener({
@@ -360,7 +362,6 @@ function processMessage(obj: HMR_ACTION_TYPES) {
360362
performFullReload(null)
361363
}
362364
onRefresh()
363-
turbopackHmr!.onTurbopackMessage(obj)
364365
break
365366
}
366367
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: 72 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,90 @@ 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+
#onUpdate() {
67+
this.#runDeferredReportHmrStart()
2568
this.#lastUpdateMsSinceEpoch = Date.now()
69+
}
70+
71+
onTurbopackMessage(msg: TurbopackMessageAction) {
72+
this.#onUpdate()
2673
const updatedModules = extractModulesFromTurbopackMessage(msg.data)
2774
for (const module of updatedModules) {
2875
this.#updatedModules.add(module)
2976
}
3077
}
3178

79+
onServerComponentChanges() {
80+
this.#onUpdate()
81+
}
82+
83+
onReloadPage() {
84+
this.#onUpdate()
85+
}
86+
87+
onPageAddRemove() {
88+
this.#onUpdate()
89+
}
90+
3291
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) {
92+
// Check that we got *any* `TurbopackMessageAction`, even if `updatedModules` is empty (not
93+
// everything gets recorded there).
94+
//
95+
// This also handles for the case where `onBuilt` gets called before `onBuilding`, which can
96+
// happen during initial page load. We should ignore this.
97+
const hasUpdates = this.#lastUpdateMsSinceEpoch != null
98+
if (!hasUpdates && this.#deferredReportHmrStartId != null) {
99+
// suppress the update entirely
100+
this.#cancelDeferredReportHmrStart()
36101
return null
37102
}
103+
this.#runDeferredReportHmrStart()
104+
38105
const result = {
106+
hasUpdates,
39107
updatedModules: this.#updatedModules,
40108
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.
44109
endMsSinceEpoch: this.#lastUpdateMsSinceEpoch ?? Date.now(),
45110
}
46111
this.#updatedModules = new Set()

0 commit comments

Comments
 (0)