From bb29b04e88ba1befa4a66e265809b0216cdbcddb Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Sun, 14 Sep 2025 17:28:28 +0900 Subject: [PATCH 1/4] fix(hmr): trigger prune event when import is removed from non hmr module --- packages/vite/src/node/plugins/importAnalysis.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vite/src/node/plugins/importAnalysis.ts b/packages/vite/src/node/plugins/importAnalysis.ts index 64a8fdce9b2826..0e5a1ce6879f1c 100644 --- a/packages/vite/src/node/plugins/importAnalysis.ts +++ b/packages/vite/src/node/plugins/importAnalysis.ts @@ -835,7 +835,7 @@ export function importAnalysisPlugin(config: ResolvedConfig): Plugin { isSelfAccepting, staticImportedUrls, ) - if (hasHMR && prunedImports) { + if (prunedImports) { handlePrunedModules(prunedImports, environment) } } From 2c47acc3547895146ae51e820ad06ae24adb0859 Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 15 Sep 2025 19:10:02 +0900 Subject: [PATCH 2/4] test: add e2e --- playground/hmr/__tests__/hmr.spec.ts | 9 +++++++++ playground/hmr/hmr.ts | 1 + playground/hmr/index.html | 1 + playground/hmr/prune/dep1.js | 7 +++++++ playground/hmr/prune/dep2-other.js | 0 playground/hmr/prune/dep2.js | 5 +++++ playground/hmr/prune/index.js | 5 +++++ 7 files changed, 28 insertions(+) create mode 100644 playground/hmr/prune/dep1.js create mode 100644 playground/hmr/prune/dep2-other.js create mode 100644 playground/hmr/prune/dep2.js create mode 100644 playground/hmr/prune/index.js diff --git a/playground/hmr/__tests__/hmr.spec.ts b/playground/hmr/__tests__/hmr.spec.ts index 499aae1b4e2cf6..92872c1e21c0a3 100644 --- a/playground/hmr/__tests__/hmr.spec.ts +++ b/playground/hmr/__tests__/hmr.spec.ts @@ -997,6 +997,15 @@ if (!isBuild) { .toMatch('parent:child') }) + test('deleting import from non-self-accepting module can trigger prune event', async () => { + await page.goto(viteTestUrl) + await expect.poll(() => page.textContent('.prune')).toMatch('init') + editFile('prune/dep1.js', (code) => + code.replace(`import './dep2.js'`, `// import './dep2.js'`), + ) + await expect.poll(() => page.textContent('.prune')).toMatch('dep2-pruned') + }) + test('import.meta.hot?.accept', async () => { await page.goto(viteTestUrl) diff --git a/playground/hmr/hmr.ts b/playground/hmr/hmr.ts index 57eb5df0ab30ea..859809801f29cd 100644 --- a/playground/hmr/hmr.ts +++ b/playground/hmr/hmr.ts @@ -7,6 +7,7 @@ import './file-delete-restore' import './optional-chaining/parent' import './intermediate-file-delete' import './circular' +import './prune' import logo from './logo.svg' import logoNoInline from './logo-no-inline.svg' import { msg as softInvalidationMsg } from './soft-invalidation' diff --git a/playground/hmr/index.html b/playground/hmr/index.html index 8bd295beb73c95..a7574ffd32ea78 100644 --- a/playground/hmr/index.html +++ b/playground/hmr/index.html @@ -45,3 +45,4 @@
+
prune/init
diff --git a/playground/hmr/prune/dep1.js b/playground/hmr/prune/dep1.js new file mode 100644 index 00000000000000..cdfa750527b394 --- /dev/null +++ b/playground/hmr/prune/dep1.js @@ -0,0 +1,7 @@ +import './dep2.js' + +// TODO: currently we need one more `import` in this module +// to trigger prune for depending module `dep2.js` since +// the prune event logic is skipped when `es-module-lexer` +// detects `imports.length === 0` +import './dep2-other.js' diff --git a/playground/hmr/prune/dep2-other.js b/playground/hmr/prune/dep2-other.js new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/playground/hmr/prune/dep2.js b/playground/hmr/prune/dep2.js new file mode 100644 index 00000000000000..3adfc460e845c9 --- /dev/null +++ b/playground/hmr/prune/dep2.js @@ -0,0 +1,5 @@ +if (import.meta.hot) { + import.meta.hot.prune(() => { + document.querySelector('.prune').textContent = 'prune/dep2-pruned' + }) +} diff --git a/playground/hmr/prune/index.js b/playground/hmr/prune/index.js new file mode 100644 index 00000000000000..f79e0d2d015aef --- /dev/null +++ b/playground/hmr/prune/index.js @@ -0,0 +1,5 @@ +import './dep1.js' + +if (import.meta.hot) { + import.meta.hot.accept(() => {}) +} From 3e3c0c4520aba21a5823fd6008dbbeac6f0b90bf Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Tue, 16 Sep 2025 15:25:03 +0900 Subject: [PATCH 3/4] chore: comment --- playground/hmr/prune/dep1.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/playground/hmr/prune/dep1.js b/playground/hmr/prune/dep1.js index cdfa750527b394..6621b014013ab3 100644 --- a/playground/hmr/prune/dep1.js +++ b/playground/hmr/prune/dep1.js @@ -1,6 +1,7 @@ import './dep2.js' -// TODO: currently we need one more `import` in this module +// TODO: https://github.com/vitejs/vite/issues/20781 +// currently we need one more `import` in this module // to trigger prune for depending module `dep2.js` since // the prune event logic is skipped when `es-module-lexer` // detects `imports.length === 0` From 7264b09a6288acf0de1f3169f891bb93014653ef Mon Sep 17 00:00:00 2001 From: Hiroshi Ogawa Date: Mon, 22 Sep 2025 11:50:37 +0900 Subject: [PATCH 4/4] test: test dispose before prune --- playground/hmr/__tests__/hmr.spec.ts | 6 ++++-- playground/hmr/index.html | 2 +- playground/hmr/prune/dep2.js | 5 ++++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/playground/hmr/__tests__/hmr.spec.ts b/playground/hmr/__tests__/hmr.spec.ts index 92872c1e21c0a3..139355368e53b1 100644 --- a/playground/hmr/__tests__/hmr.spec.ts +++ b/playground/hmr/__tests__/hmr.spec.ts @@ -999,11 +999,13 @@ if (!isBuild) { test('deleting import from non-self-accepting module can trigger prune event', async () => { await page.goto(viteTestUrl) - await expect.poll(() => page.textContent('.prune')).toMatch('init') + await expect.poll(() => page.textContent('.prune')).toMatch('prune-init') editFile('prune/dep1.js', (code) => code.replace(`import './dep2.js'`, `// import './dep2.js'`), ) - await expect.poll(() => page.textContent('.prune')).toMatch('dep2-pruned') + await expect + .poll(() => page.textContent('.prune')) + .toMatch('prune-init|dep2-disposed|dep2-pruned') }) test('import.meta.hot?.accept', async () => { diff --git a/playground/hmr/index.html b/playground/hmr/index.html index a7574ffd32ea78..e4ea468b98d67d 100644 --- a/playground/hmr/index.html +++ b/playground/hmr/index.html @@ -45,4 +45,4 @@
-
prune/init
+
prune-init
diff --git a/playground/hmr/prune/dep2.js b/playground/hmr/prune/dep2.js index 3adfc460e845c9..95db869caa5e07 100644 --- a/playground/hmr/prune/dep2.js +++ b/playground/hmr/prune/dep2.js @@ -1,5 +1,8 @@ if (import.meta.hot) { + import.meta.hot.dispose(() => { + document.querySelector('.prune').textContent += '|dep2-disposed' + }) import.meta.hot.prune(() => { - document.querySelector('.prune').textContent = 'prune/dep2-pruned' + document.querySelector('.prune').textContent += '|dep2-pruned' }) }