Skip to content

Commit 60a020e

Browse files
authored
feat(hmr): add full reload reason (#14914)
1 parent 2f39547 commit 60a020e

File tree

2 files changed

+28
-23
lines changed

2 files changed

+28
-23
lines changed

packages/vite/src/node/server/hmr.ts

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ export async function handleHMRUpdate(
142142
updateModules(shortFile, hmrContext.modules, timestamp, server)
143143
}
144144

145+
type HasDeadEnd = boolean | string
145146
export function updateModules(
146147
file: string,
147148
modules: ModuleNode[],
@@ -152,7 +153,7 @@ export function updateModules(
152153
const updates: Update[] = []
153154
const invalidatedModules = new Set<ModuleNode>()
154155
const traversedModules = new Set<ModuleNode>()
155-
let needFullReload = false
156+
let needFullReload: HasDeadEnd = false
156157

157158
for (const mod of modules) {
158159
const boundaries: { boundary: ModuleNode; acceptedVia: ModuleNode }[] = []
@@ -165,7 +166,7 @@ export function updateModules(
165166
}
166167

167168
if (hasDeadEnd) {
168-
needFullReload = true
169+
needFullReload = hasDeadEnd
169170
continue
170171
}
171172

@@ -184,10 +185,14 @@ export function updateModules(
184185
}
185186

186187
if (needFullReload) {
187-
config.logger.info(colors.green(`page reload `) + colors.dim(file), {
188-
clear: !afterInvalidation,
189-
timestamp: true,
190-
})
188+
const reason =
189+
typeof needFullReload === 'string'
190+
? colors.dim(` (${needFullReload})`)
191+
: ''
192+
config.logger.info(
193+
colors.green(`page reload `) + colors.dim(file) + reason,
194+
{ clear: !afterInvalidation, timestamp: true },
195+
)
191196
ws.send({
192197
type: 'full-reload',
193198
})
@@ -254,7 +259,7 @@ function propagateUpdate(
254259
traversedModules: Set<ModuleNode>,
255260
boundaries: { boundary: ModuleNode; acceptedVia: ModuleNode }[],
256261
currentChain: ModuleNode[] = [node],
257-
): boolean /* hasDeadEnd */ {
262+
): HasDeadEnd {
258263
if (traversedModules.has(node)) {
259264
return false
260265
}
@@ -274,9 +279,8 @@ function propagateUpdate(
274279

275280
if (node.isSelfAccepting) {
276281
boundaries.push({ boundary: node, acceptedVia: node })
277-
if (isNodeWithinCircularImports(node, currentChain)) {
278-
return true
279-
}
282+
const result = isNodeWithinCircularImports(node, currentChain)
283+
if (result) return result
280284

281285
// additionally check for CSS importers, since a PostCSS plugin like
282286
// Tailwind JIT may register any file as a dependency to a CSS file.
@@ -301,9 +305,8 @@ function propagateUpdate(
301305
// so that they do get the fresh imported module when/if they are reloaded.
302306
if (node.acceptedHmrExports) {
303307
boundaries.push({ boundary: node, acceptedVia: node })
304-
if (isNodeWithinCircularImports(node, currentChain)) {
305-
return true
306-
}
308+
const result = isNodeWithinCircularImports(node, currentChain)
309+
if (result) return result
307310
} else {
308311
if (!node.importers.size) {
309312
return true
@@ -325,9 +328,8 @@ function propagateUpdate(
325328

326329
if (importer.acceptedHmrDeps.has(node)) {
327330
boundaries.push({ boundary: importer, acceptedVia: node })
328-
if (isNodeWithinCircularImports(importer, subChain)) {
329-
return true
330-
}
331+
const result = isNodeWithinCircularImports(importer, subChain)
332+
if (result) return result
331333
continue
332334
}
333335

@@ -364,7 +366,7 @@ function isNodeWithinCircularImports(
364366
node: ModuleNode,
365367
nodeChain: ModuleNode[],
366368
currentChain: ModuleNode[] = [node],
367-
) {
369+
): HasDeadEnd {
368370
// To help visualize how each parameters work, imagine this import graph:
369371
//
370372
// A -> B -> C -> ACCEPTED -> D -> E -> NODE
@@ -405,19 +407,17 @@ function isNodeWithinCircularImports(
405407
importChain.map((m) => colors.dim(m.url)).join(' -> '),
406408
)
407409
}
408-
return true
410+
return 'circular imports'
409411
}
410412

411413
// Continue recursively
412-
if (
413-
!currentChain.includes(importer) &&
414-
isNodeWithinCircularImports(
414+
if (!currentChain.includes(importer)) {
415+
const result = isNodeWithinCircularImports(
415416
importer,
416417
nodeChain,
417418
currentChain.concat(importer),
418419
)
419-
) {
420-
return true
420+
if (result) return result
421421
}
422422
}
423423
return false

playground/hmr/__tests__/hmr.spec.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
isBuild,
88
page,
99
removeFile,
10+
serverLogs,
1011
untilBrowserLogAfter,
1112
untilUpdated,
1213
viteTestUrl,
@@ -881,6 +882,10 @@ if (import.meta.hot) {
881882
() => page.textContent('.self-accept-within-circular'),
882883
'cc',
883884
)
885+
expect(serverLogs.length).greaterThanOrEqual(1)
886+
// Match on full log not possible because of color markers
887+
expect(serverLogs.at(-1)!).toContain('page reload')
888+
expect(serverLogs.at(-1)!).toContain('(circular imports)')
884889
})
885890

886891
test('hmr should not reload if no accepted within circular imported files', async () => {

0 commit comments

Comments
 (0)