From 5bcb5ef19cd030dac95ba2dfc514b1e1ed4115c8 Mon Sep 17 00:00:00 2001 From: YunfeiHe Date: Thu, 27 Apr 2023 21:40:47 +0800 Subject: [PATCH 1/5] fix(hmr): only invalidate importers if the invalidated module is not a HMR boundary --- packages/vite/src/node/server/hmr.ts | 17 ++++++++++++----- packages/vite/src/node/server/moduleGraph.ts | 6 ++++++ playground/hmr/__tests__/hmr.spec.ts | 10 ++++++++++ playground/hmr/issue-3303/a.js | 5 +++++ playground/hmr/issue-3303/b.js | 7 +++++++ playground/hmr/issue-3303/c.js | 12 ++++++++++++ playground/hmr/issue-3303/index.html | 2 ++ playground/hmr/issue-3303/index.js | 3 +++ 8 files changed, 57 insertions(+), 5 deletions(-) create mode 100644 playground/hmr/issue-3303/a.js create mode 100644 playground/hmr/issue-3303/b.js create mode 100644 playground/hmr/issue-3303/c.js create mode 100644 playground/hmr/issue-3303/index.html create mode 100644 playground/hmr/issue-3303/index.js diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts index 42badca778b453..d1a973da60db28 100644 --- a/packages/vite/src/node/server/hmr.ts +++ b/packages/vite/src/node/server/hmr.ts @@ -144,11 +144,6 @@ export function updateModules( let needFullReload = false for (const mod of modules) { - moduleGraph.invalidateModule(mod, invalidatedModules, timestamp, true) - if (needFullReload) { - continue - } - const boundaries: { boundary: ModuleNode; acceptedVia: ModuleNode }[] = [] const hasDeadEnd = propagateUpdate(mod, traversedModules, boundaries) if (hasDeadEnd) { @@ -156,6 +151,18 @@ export function updateModules( continue } + moduleGraph.invalidateModule( + mod, + invalidatedModules, + timestamp, + true, + boundaries.map((b) => b.boundary), + ) + + if (needFullReload) { + continue + } + updates.push( ...boundaries.map(({ boundary, acceptedVia }) => ({ type: `${boundary.type}-update` as const, diff --git a/packages/vite/src/node/server/moduleGraph.ts b/packages/vite/src/node/server/moduleGraph.ts index 804e38bc2c3cc7..5c8496bb760812 100644 --- a/packages/vite/src/node/server/moduleGraph.ts +++ b/packages/vite/src/node/server/moduleGraph.ts @@ -121,6 +121,7 @@ export class ModuleGraph { seen: Set = new Set(), timestamp: number = Date.now(), isHmr: boolean = false, + hmrBoundaries: ModuleNode[] = [], ): void { if (seen.has(mod)) { return @@ -139,6 +140,11 @@ export class ModuleGraph { mod.ssrTransformResult = null mod.ssrModule = null mod.ssrError = null + + // TODO: If the module is a HMR boundary, we don't need to invalidate its importer. Because... + if (hmrBoundaries.includes(mod)) { + return + } mod.importers.forEach((importer) => { if (!importer.acceptedHmrDeps.has(mod)) { this.invalidateModule(importer, seen, timestamp, isHmr) diff --git a/playground/hmr/__tests__/hmr.spec.ts b/playground/hmr/__tests__/hmr.spec.ts index a7fbbad80ae90e..57d457547f5d6f 100644 --- a/playground/hmr/__tests__/hmr.spec.ts +++ b/playground/hmr/__tests__/hmr.spec.ts @@ -786,4 +786,14 @@ if (import.meta.hot) { ) await untilUpdated(() => el.textContent(), '2') }) + + test('issue-3303', async () => { + await page.goto(viteTestUrl + '/issue-3303/index.html') + const el = await page.$('.issue-3303') + expect(await el.textContent()).toBe('c') + editFile('issue-3303/c.js', (code) => + code.replace(`export const c = 'c'`, `export const c = 'cc'`), + ) + await untilUpdated(() => el.textContent(), 'cc') + }) } diff --git a/playground/hmr/issue-3303/a.js b/playground/hmr/issue-3303/a.js new file mode 100644 index 00000000000000..a559b739d9f253 --- /dev/null +++ b/playground/hmr/issue-3303/a.js @@ -0,0 +1,5 @@ +import { b } from './b' + +export const a = { + b, +} diff --git a/playground/hmr/issue-3303/b.js b/playground/hmr/issue-3303/b.js new file mode 100644 index 00000000000000..4f5a135418728c --- /dev/null +++ b/playground/hmr/issue-3303/b.js @@ -0,0 +1,7 @@ +import { c } from './c' + +const b = { + c, +} + +export { b } diff --git a/playground/hmr/issue-3303/c.js b/playground/hmr/issue-3303/c.js new file mode 100644 index 00000000000000..829450cfa3a4c7 --- /dev/null +++ b/playground/hmr/issue-3303/c.js @@ -0,0 +1,12 @@ +import './b' + +export const c = 'c' + +function render(content) { + document.querySelector('.issue-3303').textContent = content +} +render(c) + +import.meta.hot?.accept((nextExports) => { + render(nextExports.c) +}) diff --git a/playground/hmr/issue-3303/index.html b/playground/hmr/issue-3303/index.html new file mode 100644 index 00000000000000..630e4d3fcbb727 --- /dev/null +++ b/playground/hmr/issue-3303/index.html @@ -0,0 +1,2 @@ + +
diff --git a/playground/hmr/issue-3303/index.js b/playground/hmr/issue-3303/index.js new file mode 100644 index 00000000000000..604c0a3518932b --- /dev/null +++ b/playground/hmr/issue-3303/index.js @@ -0,0 +1,3 @@ +import { a } from './a' + +console.log(a) From c5a547ab0f2b5ab2fdc9c7bc3aca67744d764357 Mon Sep 17 00:00:00 2001 From: YunfeiHe Date: Thu, 27 Apr 2023 23:49:56 +0800 Subject: [PATCH 2/5] better comment --- packages/vite/src/node/server/moduleGraph.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/server/moduleGraph.ts b/packages/vite/src/node/server/moduleGraph.ts index 5c8496bb760812..9bc413ad4af8af 100644 --- a/packages/vite/src/node/server/moduleGraph.ts +++ b/packages/vite/src/node/server/moduleGraph.ts @@ -141,7 +141,7 @@ export class ModuleGraph { mod.ssrModule = null mod.ssrError = null - // TODO: If the module is a HMR boundary, we don't need to invalidate its importer. Because... + // Fix #3033 if (hmrBoundaries.includes(mod)) { return } From 520c6d133065058aa64a0123424df9af1393e872 Mon Sep 17 00:00:00 2001 From: YunfeiHe Date: Sat, 29 Apr 2023 02:22:45 +0800 Subject: [PATCH 3/5] Fix issue number --- playground/hmr/__tests__/hmr.spec.ts | 8 ++++---- playground/hmr/{issue-3303 => issue-3033}/a.js | 0 playground/hmr/{issue-3303 => issue-3033}/b.js | 0 playground/hmr/{issue-3303 => issue-3033}/c.js | 0 playground/hmr/{issue-3303 => issue-3033}/index.html | 2 +- playground/hmr/{issue-3303 => issue-3033}/index.js | 0 6 files changed, 5 insertions(+), 5 deletions(-) rename playground/hmr/{issue-3303 => issue-3033}/a.js (100%) rename playground/hmr/{issue-3303 => issue-3033}/b.js (100%) rename playground/hmr/{issue-3303 => issue-3033}/c.js (100%) rename playground/hmr/{issue-3303 => issue-3033}/index.html (60%) rename playground/hmr/{issue-3303 => issue-3033}/index.js (100%) diff --git a/playground/hmr/__tests__/hmr.spec.ts b/playground/hmr/__tests__/hmr.spec.ts index 57d457547f5d6f..a80f711dbdcd2a 100644 --- a/playground/hmr/__tests__/hmr.spec.ts +++ b/playground/hmr/__tests__/hmr.spec.ts @@ -787,11 +787,11 @@ if (import.meta.hot) { await untilUpdated(() => el.textContent(), '2') }) - test('issue-3303', async () => { - await page.goto(viteTestUrl + '/issue-3303/index.html') - const el = await page.$('.issue-3303') + test('issue-3033', async () => { + await page.goto(viteTestUrl + '/issue-3033/index.html') + const el = await page.$('.issue-3033') expect(await el.textContent()).toBe('c') - editFile('issue-3303/c.js', (code) => + editFile('issue-3033/c.js', (code) => code.replace(`export const c = 'c'`, `export const c = 'cc'`), ) await untilUpdated(() => el.textContent(), 'cc') diff --git a/playground/hmr/issue-3303/a.js b/playground/hmr/issue-3033/a.js similarity index 100% rename from playground/hmr/issue-3303/a.js rename to playground/hmr/issue-3033/a.js diff --git a/playground/hmr/issue-3303/b.js b/playground/hmr/issue-3033/b.js similarity index 100% rename from playground/hmr/issue-3303/b.js rename to playground/hmr/issue-3033/b.js diff --git a/playground/hmr/issue-3303/c.js b/playground/hmr/issue-3033/c.js similarity index 100% rename from playground/hmr/issue-3303/c.js rename to playground/hmr/issue-3033/c.js diff --git a/playground/hmr/issue-3303/index.html b/playground/hmr/issue-3033/index.html similarity index 60% rename from playground/hmr/issue-3303/index.html rename to playground/hmr/issue-3033/index.html index 630e4d3fcbb727..aa40111b26c214 100644 --- a/playground/hmr/issue-3303/index.html +++ b/playground/hmr/issue-3033/index.html @@ -1,2 +1,2 @@ -
+
diff --git a/playground/hmr/issue-3303/index.js b/playground/hmr/issue-3033/index.js similarity index 100% rename from playground/hmr/issue-3303/index.js rename to playground/hmr/issue-3033/index.js From 45fa189c570f413e927b218e64e0cb782a1ff9da Mon Sep 17 00:00:00 2001 From: YunfeiHe Date: Sat, 29 Apr 2023 02:31:20 +0800 Subject: [PATCH 4/5] Fix test --- playground/hmr/issue-3033/c.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playground/hmr/issue-3033/c.js b/playground/hmr/issue-3033/c.js index 829450cfa3a4c7..18ebe62aa9f0a7 100644 --- a/playground/hmr/issue-3033/c.js +++ b/playground/hmr/issue-3033/c.js @@ -3,7 +3,7 @@ import './b' export const c = 'c' function render(content) { - document.querySelector('.issue-3303').textContent = content + document.querySelector('.issue-3033').textContent = content } render(c) From 5804e8917ba947bf4453411aa18b302346988250 Mon Sep 17 00:00:00 2001 From: ArnaudBarre Date: Fri, 16 Jun 2023 02:43:59 +0200 Subject: [PATCH 5/5] invalidate module in case of dead end --- packages/vite/src/node/server/hmr.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/vite/src/node/server/hmr.ts b/packages/vite/src/node/server/hmr.ts index d1a973da60db28..e72b1ebdf05338 100644 --- a/packages/vite/src/node/server/hmr.ts +++ b/packages/vite/src/node/server/hmr.ts @@ -146,10 +146,6 @@ export function updateModules( for (const mod of modules) { const boundaries: { boundary: ModuleNode; acceptedVia: ModuleNode }[] = [] const hasDeadEnd = propagateUpdate(mod, traversedModules, boundaries) - if (hasDeadEnd) { - needFullReload = true - continue - } moduleGraph.invalidateModule( mod, @@ -163,6 +159,11 @@ export function updateModules( continue } + if (hasDeadEnd) { + needFullReload = true + continue + } + updates.push( ...boundaries.map(({ boundary, acceptedVia }) => ({ type: `${boundary.type}-update` as const,