@@ -140,6 +140,7 @@ export function updateModules(
140
140
) : void {
141
141
const updates : Update [ ] = [ ]
142
142
const invalidatedModules = new Set < ModuleNode > ( )
143
+ const traversedModules = new Set < ModuleNode > ( )
143
144
let needFullReload = false
144
145
145
146
for ( const mod of modules ) {
@@ -148,18 +149,15 @@ export function updateModules(
148
149
continue
149
150
}
150
151
151
- const boundaries = new Set < {
152
- boundary : ModuleNode
153
- acceptedVia : ModuleNode
154
- } > ( )
155
- const hasDeadEnd = propagateUpdate ( mod , boundaries )
152
+ const boundaries : { boundary : ModuleNode ; acceptedVia : ModuleNode } [ ] = [ ]
153
+ const hasDeadEnd = propagateUpdate ( mod , traversedModules , boundaries )
156
154
if ( hasDeadEnd ) {
157
155
needFullReload = true
158
156
continue
159
157
}
160
158
161
159
updates . push (
162
- ...[ ... boundaries ] . map ( ( { boundary, acceptedVia } ) => ( {
160
+ ...boundaries . map ( ( { boundary, acceptedVia } ) => ( {
163
161
type : `${ boundary . type } -update` as const ,
164
162
timestamp,
165
163
path : normalizeHmrUrl ( boundary . url ) ,
@@ -231,12 +229,15 @@ function areAllImportsAccepted(
231
229
232
230
function propagateUpdate (
233
231
node : ModuleNode ,
234
- boundaries : Set < {
235
- boundary : ModuleNode
236
- acceptedVia : ModuleNode
237
- } > ,
232
+ traversedModules : Set < ModuleNode > ,
233
+ boundaries : { boundary : ModuleNode ; acceptedVia : ModuleNode } [ ] ,
238
234
currentChain : ModuleNode [ ] = [ node ] ,
239
235
) : boolean /* hasDeadEnd */ {
236
+ if ( traversedModules . has ( node ) ) {
237
+ return false
238
+ }
239
+ traversedModules . add ( node )
240
+
240
241
// #7561
241
242
// if the imports of `node` have not been analyzed, then `node` has not
242
243
// been loaded in the browser and we should stop propagation.
@@ -250,16 +251,18 @@ function propagateUpdate(
250
251
}
251
252
252
253
if ( node . isSelfAccepting ) {
253
- boundaries . add ( {
254
- boundary : node ,
255
- acceptedVia : node ,
256
- } )
254
+ boundaries . push ( { boundary : node , acceptedVia : node } )
257
255
258
256
// additionally check for CSS importers, since a PostCSS plugin like
259
257
// Tailwind JIT may register any file as a dependency to a CSS file.
260
258
for ( const importer of node . importers ) {
261
259
if ( isCSSRequest ( importer . url ) && ! currentChain . includes ( importer ) ) {
262
- propagateUpdate ( importer , boundaries , currentChain . concat ( importer ) )
260
+ propagateUpdate (
261
+ importer ,
262
+ traversedModules ,
263
+ boundaries ,
264
+ currentChain . concat ( importer ) ,
265
+ )
263
266
}
264
267
}
265
268
@@ -272,10 +275,7 @@ function propagateUpdate(
272
275
// Also, the imported module (this one) must be updated before the importers,
273
276
// so that they do get the fresh imported module when/if they are reloaded.
274
277
if ( node . acceptedHmrExports ) {
275
- boundaries . add ( {
276
- boundary : node ,
277
- acceptedVia : node ,
278
- } )
278
+ boundaries . push ( { boundary : node , acceptedVia : node } )
279
279
} else {
280
280
if ( ! node . importers . size ) {
281
281
return true
@@ -295,10 +295,7 @@ function propagateUpdate(
295
295
for ( const importer of node . importers ) {
296
296
const subChain = currentChain . concat ( importer )
297
297
if ( importer . acceptedHmrDeps . has ( node ) ) {
298
- boundaries . add ( {
299
- boundary : importer ,
300
- acceptedVia : node ,
301
- } )
298
+ boundaries . push ( { boundary : importer , acceptedVia : node } )
302
299
continue
303
300
}
304
301
@@ -317,7 +314,7 @@ function propagateUpdate(
317
314
return true
318
315
}
319
316
320
- if ( propagateUpdate ( importer , boundaries , subChain ) ) {
317
+ if ( propagateUpdate ( importer , traversedModules , boundaries , subChain ) ) {
321
318
return true
322
319
}
323
320
}
0 commit comments