From 3b912fbcc8a1b7b08b4f8aa2ba0b952a4d4c772b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arnaud=20Barr=C3=A9?= Date: Wed, 5 Apr 2023 09:53:51 +0200 Subject: [PATCH] perf(hmr): keep track of already traversed modules when propagating update (#12658) --- packages/vite/src/node/server/hmr.ts | 45 +++++++++++++--------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts index 226ea5a365cda8..42badca778b453 100644 --- a/packages/vite/src/node/server/hmr.ts +++ b/packages/vite/src/node/server/hmr.ts @@ -140,6 +140,7 @@ export function updateModules( ): void { const updates: Update[] = [] const invalidatedModules = new Set() + const traversedModules = new Set() let needFullReload = false for (const mod of modules) { @@ -148,18 +149,15 @@ export function updateModules( continue } - const boundaries = new Set<{ - boundary: ModuleNode - acceptedVia: ModuleNode - }>() - const hasDeadEnd = propagateUpdate(mod, boundaries) + const boundaries: { boundary: ModuleNode; acceptedVia: ModuleNode }[] = [] + const hasDeadEnd = propagateUpdate(mod, traversedModules, boundaries) if (hasDeadEnd) { needFullReload = true continue } updates.push( - ...[...boundaries].map(({ boundary, acceptedVia }) => ({ + ...boundaries.map(({ boundary, acceptedVia }) => ({ type: `${boundary.type}-update` as const, timestamp, path: normalizeHmrUrl(boundary.url), @@ -231,12 +229,15 @@ function areAllImportsAccepted( function propagateUpdate( node: ModuleNode, - boundaries: Set<{ - boundary: ModuleNode - acceptedVia: ModuleNode - }>, + traversedModules: Set, + boundaries: { boundary: ModuleNode; acceptedVia: ModuleNode }[], currentChain: ModuleNode[] = [node], ): boolean /* hasDeadEnd */ { + if (traversedModules.has(node)) { + return false + } + traversedModules.add(node) + // #7561 // if the imports of `node` have not been analyzed, then `node` has not // been loaded in the browser and we should stop propagation. @@ -250,16 +251,18 @@ function propagateUpdate( } if (node.isSelfAccepting) { - boundaries.add({ - boundary: node, - acceptedVia: node, - }) + boundaries.push({ boundary: node, acceptedVia: node }) // additionally check for CSS importers, since a PostCSS plugin like // Tailwind JIT may register any file as a dependency to a CSS file. for (const importer of node.importers) { if (isCSSRequest(importer.url) && !currentChain.includes(importer)) { - propagateUpdate(importer, boundaries, currentChain.concat(importer)) + propagateUpdate( + importer, + traversedModules, + boundaries, + currentChain.concat(importer), + ) } } @@ -272,10 +275,7 @@ function propagateUpdate( // Also, the imported module (this one) must be updated before the importers, // so that they do get the fresh imported module when/if they are reloaded. if (node.acceptedHmrExports) { - boundaries.add({ - boundary: node, - acceptedVia: node, - }) + boundaries.push({ boundary: node, acceptedVia: node }) } else { if (!node.importers.size) { return true @@ -295,10 +295,7 @@ function propagateUpdate( for (const importer of node.importers) { const subChain = currentChain.concat(importer) if (importer.acceptedHmrDeps.has(node)) { - boundaries.add({ - boundary: importer, - acceptedVia: node, - }) + boundaries.push({ boundary: importer, acceptedVia: node }) continue } @@ -317,7 +314,7 @@ function propagateUpdate( return true } - if (propagateUpdate(importer, boundaries, subChain)) { + if (propagateUpdate(importer, traversedModules, boundaries, subChain)) { return true } }