-
Notifications
You must be signed in to change notification settings - Fork 28.2k
/
Copy pathturbopack-hot-reloader-common.ts
83 lines (72 loc) · 2.42 KB
/
turbopack-hot-reloader-common.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import type { TurbopackMessageAction } from '../../../../server/dev/hot-reloader-types'
import type { Update as TurbopackUpdate } from '../../../../build/swc/types'
interface HmrUpdate {
updatedModules: Set<string>
startMsSinceEpoch: number
endMsSinceEpoch: number
}
export class TurbopackHmr {
#updatedModules: Set<string>
#startMsSinceEpoch: number | undefined
#lastUpdateMsSinceEpoch: number | undefined
constructor() {
this.#updatedModules = new Set()
}
onBuilding() {
this.#lastUpdateMsSinceEpoch = undefined
this.#startMsSinceEpoch = Date.now()
}
onTurbopackMessage(msg: TurbopackMessageAction) {
this.#lastUpdateMsSinceEpoch = Date.now()
const updatedModules = extractModulesFromTurbopackMessage(msg.data)
for (const module of updatedModules) {
this.#updatedModules.add(module)
}
}
onBuilt(): HmrUpdate | null {
// it's possible for `this.#startMsSinceEpoch` to not be set if this was the initial
// computation, just return null in this case.
if (this.#startMsSinceEpoch == null) {
return null
}
const result = {
updatedModules: this.#updatedModules,
startMsSinceEpoch: this.#startMsSinceEpoch!,
// Turbopack has a debounce which causes every BUILT message to appear
// 30ms late. We don't want to include this latency in our reporting, so
// prefer to use the last TURBOPACK_MESSAGE time.
endMsSinceEpoch: this.#lastUpdateMsSinceEpoch ?? Date.now(),
}
this.#updatedModules = new Set()
return result
}
}
function extractModulesFromTurbopackMessage(
data: TurbopackUpdate | TurbopackUpdate[]
): Set<string> {
const updatedModules: Set<string> = 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) {
for (const name of Object.keys(mergedUpdate.entries)) {
const res = /(.*)\s+\[.*/.exec(name)
if (res === null) {
console.error(
'[Turbopack HMR] Expected module to match pattern: ' + name
)
continue
}
updatedModules.add(res[1])
}
}
}
return updatedModules
}