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

Skip to content

Commit bc42a78

Browse files
committed
WIP refactor(HMR clients): Encapsulate some of the turbopack state tracking into a shared TurbopackHmr class
1 parent 43fbb5e commit bc42a78

File tree

5 files changed

+120
-95
lines changed

5 files changed

+120
-95
lines changed

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

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import type {
4242
HMR_ACTION_TYPES,
4343
TurbopackMsgToBrowser,
4444
} from '../../../../server/dev/hot-reloader-types'
45-
import { extractModulesFromTurbopackMessage } from '../../../../server/dev/extract-modules-from-turbopack-message'
4645
import { REACT_REFRESH_FULL_RELOAD_FROM_ERROR } from '../shared'
4746
import type { HydrationErrorState } from '../../errors/hydration-error-info'
4847
import type { DebugInfo } from '../types'
@@ -53,6 +52,7 @@ import { handleDevBuildIndicatorHmrEvents } from '../../../dev/dev-build-indicat
5352
import type { GlobalErrorComponent } from '../../error-boundary'
5453
import type { DevIndicatorServerState } from '../../../../server/dev/dev-indicator-server-state'
5554
import reportHmrLatency from '../utils/report-hmr-latency'
55+
import { TurbopackHmr } from '../utils/turbopack-hot-reloader-common'
5656

5757
export interface Dispatcher {
5858
onBuildOk(): void
@@ -68,9 +68,10 @@ export interface Dispatcher {
6868
let mostRecentCompilationHash: any = null
6969
let __nextDevClientId = Math.round(Math.random() * 100 + Date.now())
7070
let reloading = false
71-
let startLatency: number | null = null
72-
let turbopackLastUpdateLatency: number | null = null
73-
let turbopackUpdatedModules: Set<string> = new Set()
71+
let webpackStartMsSinceEpoch: number | null = null
72+
const turbopackHmr: TurbopackHmr | null = process.env.TURBOPACK
73+
? new TurbopackHmr()
74+
: null
7475

7576
let pendingHotUpdateWebpack = Promise.resolve()
7677
let resolvePendingHotUpdateWebpack: () => void = () => {}
@@ -93,7 +94,12 @@ function handleSuccessfulHotUpdateWebpack(
9394
) {
9495
resolvePendingHotUpdateWebpack()
9596
dispatcher.onBuildOk()
96-
reportHmrLatency(sendMessage, updatedModules, startLatency!, Date.now())
97+
reportHmrLatency(
98+
sendMessage,
99+
updatedModules,
100+
webpackStartMsSinceEpoch!,
101+
Date.now()
102+
)
97103

98104
dispatcher.onRefresh()
99105
}
@@ -172,7 +178,7 @@ function tryApplyUpdates(
172178
if (!isUpdateAvailable() || !canApplyUpdates()) {
173179
resolvePendingHotUpdateWebpack()
174180
dispatcher.onBuildOk()
175-
reportHmrLatency(sendMessage, [], startLatency!, Date.now())
181+
reportHmrLatency(sendMessage, [], webpackStartMsSinceEpoch!, Date.now())
176182
return
177183
}
178184

@@ -282,12 +288,13 @@ function processMessage(
282288

283289
function handleHotUpdate() {
284290
if (process.env.TURBOPACK) {
291+
const built = turbopackHmr!.onBuilt()
285292
dispatcher.onBuildOk()
286293
reportHmrLatency(
287294
sendMessage,
288-
[...turbopackUpdatedModules],
289-
startLatency!,
290-
turbopackLastUpdateLatency ?? Date.now()
295+
[...built.updatedModules],
296+
built.startMsSinceEpoch,
297+
built.endMsSinceEpoch
291298
)
292299
} else {
293300
tryApplyUpdates(
@@ -331,10 +338,10 @@ function processMessage(
331338
break
332339
}
333340
case HMR_ACTIONS_SENT_TO_BROWSER.BUILDING: {
334-
startLatency = Date.now()
335-
turbopackLastUpdateLatency = null
336-
turbopackUpdatedModules.clear()
337-
if (!process.env.TURBOPACK) {
341+
if (process.env.TURBOPACK) {
342+
turbopackHmr!.onBuilding()
343+
} else {
344+
webpackStartMsSinceEpoch = Date.now()
338345
setPendingHotUpdateWebpack()
339346
}
340347
console.log('[Fast Refresh] rebuilding')
@@ -430,10 +437,7 @@ function processMessage(
430437
console.warn(REACT_REFRESH_FULL_RELOAD_FROM_ERROR)
431438
performFullReload(null, sendMessage)
432439
}
433-
for (const module of extractModulesFromTurbopackMessage(obj.data)) {
434-
turbopackUpdatedModules.add(module)
435-
}
436-
turbopackLastUpdateLatency = Date.now()
440+
turbopackHmr!.onTurbopackMessage(obj)
437441
break
438442
}
439443
// TODO-APP: make server component change more granular

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

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -46,14 +46,17 @@ import type {
4646
HMR_ACTION_TYPES,
4747
TurbopackMsgToBrowser,
4848
} from '../../../../server/dev/hot-reloader-types'
49-
import { extractModulesFromTurbopackMessage } from '../../../../server/dev/extract-modules-from-turbopack-message'
5049
import {
5150
REACT_REFRESH_FULL_RELOAD,
5251
REACT_REFRESH_FULL_RELOAD_FROM_ERROR,
5352
reportInvalidHmrMessage,
5453
} from '../shared'
5554
import { RuntimeErrorHandler } from '../../errors/runtime-error-handler'
5655
import reportHmrLatency from '../utils/report-hmr-latency'
56+
import {
57+
extractModulesFromTurbopackMessage,
58+
TurbopackHmr,
59+
} from '../utils/turbopack-hot-reloader-common'
5760
// This alternative WebpackDevServer combines the functionality of:
5861
// https://github.com/webpack/webpack-dev-server/blob/webpack-1/client/index.js
5962
// https://github.com/webpack/webpack/blob/webpack-1/hot/dev-server.js
@@ -126,12 +129,13 @@ function clearOutdatedErrors() {
126129
function handleSuccess() {
127130
clearOutdatedErrors()
128131

129-
if (!process.env.TURBOPACK) {
132+
if (process.env.TURBOPACK) {
133+
const built = turbopackHmr!.onBuilt()
130134
reportHmrLatency(
131135
sendMessage,
132-
[...turbopackUpdatedModules],
133-
startLatency!,
134-
turbopackLastUpdateLatency ?? Date.now()
136+
[...built.updatedModules],
137+
built.startMsSinceEpoch,
138+
built.endMsSinceEpoch
135139
)
136140
onBuildOk()
137141
} else {
@@ -219,9 +223,10 @@ function handleErrors(errors: any) {
219223
}
220224
}
221225

222-
let startLatency: number | null = null
223-
let turbopackLastUpdateLatency: number | null = null
224-
let turbopackUpdatedModules: Set<string> = new Set()
226+
let webpackStartMsSinceEpoch: number | null = null
227+
const turbopackHmr: TurbopackHmr | null = process.env.TURBOPACK
228+
? new TurbopackHmr()
229+
: null
225230
let isrManifest: Record<string, boolean> = {}
226231

227232
function onBeforeFastRefresh(updatedModules: string[]) {
@@ -243,8 +248,8 @@ function onFastRefresh(updatedModules: ReadonlyArray<string> = []) {
243248
reportHmrLatency(
244249
sendMessage,
245250
updatedModules,
246-
startLatency!,
247-
turbopackLastUpdateLatency ?? Date.now()
251+
webpackStartMsSinceEpoch!,
252+
Date.now()
248253
)
249254
}
250255

@@ -286,9 +291,11 @@ function processMessage(obj: HMR_ACTION_TYPES) {
286291
break
287292
}
288293
case HMR_ACTIONS_SENT_TO_BROWSER.BUILDING: {
289-
startLatency = Date.now()
290-
turbopackLastUpdateLatency = null
291-
turbopackUpdatedModules.clear()
294+
if (process.env.TURBOPACK) {
295+
turbopackHmr!.onBuilding()
296+
} else {
297+
webpackStartMsSinceEpoch = Date.now()
298+
}
292299
console.log('[Fast Refresh] rebuilding')
293300
break
294301
}
@@ -373,10 +380,7 @@ function processMessage(obj: HMR_ACTION_TYPES) {
373380
performFullReload(null)
374381
}
375382
onRefresh()
376-
for (const module of updatedModules) {
377-
turbopackUpdatedModules.add(module)
378-
}
379-
turbopackLastUpdateLatency = Date.now()
383+
turbopackHmr!.onTurbopackMessage(obj)
380384
break
381385
}
382386
default: {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import type { TurbopackMessageAction } from '../../../../server/dev/hot-reloader-types'
2+
import type { Update as TurbopackUpdate } from '../../../../build/swc/types'
3+
4+
interface Built {
5+
updatedModules: Set<string>
6+
startMsSinceEpoch: number
7+
endMsSinceEpoch: number
8+
}
9+
10+
export class TurbopackHmr {
11+
#updatedModules: Set<string>
12+
#startMsSinceEpoch: number | undefined
13+
#lastUpdateMsSinceEpoch: number | undefined
14+
15+
constructor() {
16+
this.#updatedModules = new Set()
17+
}
18+
19+
onBuilding() {
20+
this.#lastUpdateMsSinceEpoch = undefined
21+
this.#startMsSinceEpoch = Date.now()
22+
}
23+
24+
onTurbopackMessage(msg: TurbopackMessageAction) {
25+
this.#lastUpdateMsSinceEpoch = Date.now()
26+
const updatedModules = extractModulesFromTurbopackMessage(msg.data)
27+
for (const module of updatedModules) {
28+
this.#updatedModules.add(module)
29+
}
30+
}
31+
32+
onBuilt(): Built {
33+
const result = {
34+
updatedModules: this.#updatedModules,
35+
startMsSinceEpoch: this.#startMsSinceEpoch!,
36+
// Turbopack has a debounce which causes every BUILT message to appear
37+
// 30ms late. We don't want to include this latency in our reporting, so
38+
// prefer to use the last TURBOPACK_MESSAGE time.
39+
endMsSinceEpoch: this.#lastUpdateMsSinceEpoch ?? Date.now(),
40+
}
41+
this.#updatedModules = new Set()
42+
return result
43+
}
44+
}
45+
46+
export function extractModulesFromTurbopackMessage(
47+
data: TurbopackUpdate | TurbopackUpdate[]
48+
): Set<string> {
49+
const updatedModules: Set<string> = new Set()
50+
51+
const updates = Array.isArray(data) ? data : [data]
52+
for (const update of updates) {
53+
// TODO this won't capture changes to CSS since they don't result in a "merged" update
54+
if (
55+
update.type !== 'partial' ||
56+
update.instruction.type !== 'ChunkListUpdate' ||
57+
update.instruction.merged === undefined
58+
) {
59+
continue
60+
}
61+
62+
for (const mergedUpdate of update.instruction.merged) {
63+
for (const name of Object.keys(mergedUpdate.entries)) {
64+
const res = /(.*)\s+\[.*/.exec(name)
65+
if (res === null) {
66+
console.error(
67+
'[Turbopack HMR] Expected module to match pattern: ' + name
68+
)
69+
continue
70+
}
71+
72+
updatedModules.add(res[1])
73+
}
74+
}
75+
}
76+
77+
return updatedModules
78+
}

packages/next/src/client/components/react-dev-overlay/utils/use-websocket.ts

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -121,29 +121,3 @@ export function useWebsocketPing(
121121
return () => clearInterval(interval)
122122
}, [tree, sendMessage])
123123
}
124-
125-
export function reportHmrLatency(
126-
sendMessage: (message: string) => void,
127-
updatedModules: ReadonlyArray<string>,
128-
startMsSinceEpoch: number,
129-
endMsSinceEpoch: number
130-
) {
131-
const latencyMs = endMsSinceEpoch - startMsSinceEpoch
132-
console.log(`[Fast Refresh] done in ${latencyMs}ms`)
133-
sendMessage(
134-
JSON.stringify({
135-
event: 'client-hmr-latency',
136-
id: window.__nextDevClientId,
137-
startTime: startMsSinceEpoch,
138-
endTime: endMsSinceEpoch,
139-
page: window.location.pathname,
140-
updatedModules,
141-
// Whether the page (tab) was hidden at the time the event occurred.
142-
// This can impact the accuracy of the event's timing.
143-
isPageHidden: document.visibilityState === 'hidden',
144-
})
145-
)
146-
if (self.__NEXT_HMR_LATENCY_CB) {
147-
self.__NEXT_HMR_LATENCY_CB(latencyMs)
148-
}
149-
}

packages/next/src/server/dev/extract-modules-from-turbopack-message.ts

Lines changed: 0 additions & 35 deletions
This file was deleted.

0 commit comments

Comments
 (0)