@@ -140,6 +140,7 @@ export function updateModules(
140140) : void {
141141 const updates : Update [ ] = [ ]
142142 const invalidatedModules = new Set < ModuleNode > ( )
143+ const traversedModules = new Set < ModuleNode > ( )
143144 let needFullReload = false
144145
145146 for ( const mod of modules ) {
@@ -148,18 +149,15 @@ export function updateModules(
148149 continue
149150 }
150151
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 )
156154 if ( hasDeadEnd ) {
157155 needFullReload = true
158156 continue
159157 }
160158
161159 updates . push (
162- ...[ ... boundaries ] . map ( ( { boundary, acceptedVia } ) => ( {
160+ ...boundaries . map ( ( { boundary, acceptedVia } ) => ( {
163161 type : `${ boundary . type } -update` as const ,
164162 timestamp,
165163 path : normalizeHmrUrl ( boundary . url ) ,
@@ -231,12 +229,15 @@ function areAllImportsAccepted(
231229
232230function propagateUpdate (
233231 node : ModuleNode ,
234- boundaries : Set < {
235- boundary : ModuleNode
236- acceptedVia : ModuleNode
237- } > ,
232+ traversedModules : Set < ModuleNode > ,
233+ boundaries : { boundary : ModuleNode ; acceptedVia : ModuleNode } [ ] ,
238234 currentChain : ModuleNode [ ] = [ node ] ,
239235) : boolean /* hasDeadEnd */ {
236+ if ( traversedModules . has ( node ) ) {
237+ return false
238+ }
239+ traversedModules . add ( node )
240+
240241 // #7561
241242 // if the imports of `node` have not been analyzed, then `node` has not
242243 // been loaded in the browser and we should stop propagation.
@@ -250,16 +251,18 @@ function propagateUpdate(
250251 }
251252
252253 if ( node . isSelfAccepting ) {
253- boundaries . add ( {
254- boundary : node ,
255- acceptedVia : node ,
256- } )
254+ boundaries . push ( { boundary : node , acceptedVia : node } )
257255
258256 // additionally check for CSS importers, since a PostCSS plugin like
259257 // Tailwind JIT may register any file as a dependency to a CSS file.
260258 for ( const importer of node . importers ) {
261259 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+ )
263266 }
264267 }
265268
@@ -272,10 +275,7 @@ function propagateUpdate(
272275 // Also, the imported module (this one) must be updated before the importers,
273276 // so that they do get the fresh imported module when/if they are reloaded.
274277 if ( node . acceptedHmrExports ) {
275- boundaries . add ( {
276- boundary : node ,
277- acceptedVia : node ,
278- } )
278+ boundaries . push ( { boundary : node , acceptedVia : node } )
279279 } else {
280280 if ( ! node . importers . size ) {
281281 return true
@@ -295,10 +295,7 @@ function propagateUpdate(
295295 for ( const importer of node . importers ) {
296296 const subChain = currentChain . concat ( importer )
297297 if ( importer . acceptedHmrDeps . has ( node ) ) {
298- boundaries . add ( {
299- boundary : importer ,
300- acceptedVia : node ,
301- } )
298+ boundaries . push ( { boundary : importer , acceptedVia : node } )
302299 continue
303300 }
304301
@@ -317,7 +314,7 @@ function propagateUpdate(
317314 return true
318315 }
319316
320- if ( propagateUpdate ( importer , boundaries , subChain ) ) {
317+ if ( propagateUpdate ( importer , traversedModules , boundaries , subChain ) ) {
321318 return true
322319 }
323320 }
0 commit comments