diff --git a/playground/file-delete-restore/App.jsx b/playground/file-delete-restore/App.jsx
deleted file mode 100644
index de41c853cdc3ed..00000000000000
--- a/playground/file-delete-restore/App.jsx
+++ /dev/null
@@ -1,12 +0,0 @@
-import { useState } from 'react'
-import Child from './Child'
-
-function App() {
- return (
-
-
-
- )
-}
-
-export default App
diff --git a/playground/file-delete-restore/Child.jsx b/playground/file-delete-restore/Child.jsx
deleted file mode 100644
index fa6e1aefb6d829..00000000000000
--- a/playground/file-delete-restore/Child.jsx
+++ /dev/null
@@ -1,3 +0,0 @@
-export default function Child() {
- return Child state 1
-}
diff --git a/playground/file-delete-restore/__tests__/file-delete-restore.spec.ts b/playground/file-delete-restore/__tests__/file-delete-restore.spec.ts
deleted file mode 100644
index 90887f93461770..00000000000000
--- a/playground/file-delete-restore/__tests__/file-delete-restore.spec.ts
+++ /dev/null
@@ -1,60 +0,0 @@
-import { test } from 'vitest'
-import {
- addFile,
- editFile,
- isBuild,
- page,
- removeFile,
- untilUpdated,
-} from '~utils'
-
-test.runIf(isBuild)(
- 'should hmr when file is deleted and restored',
- async () => {
- await untilUpdated(() => page.textContent('p'), 'Child state 1')
-
- editFile('Child.jsx', (code) =>
- code.replace('Child state 1', 'Child state 2'),
- )
-
- await untilUpdated(() => page.textContent('p'), 'Child state 2')
-
- editFile('App.jsx', (code) =>
- code
- .replace(`import Child from './Child'`, '')
- .replace(``, 'Child deleted
'),
- )
- removeFile('Child.jsx')
- await untilUpdated(() => page.textContent('p'), 'Child deleted')
-
- // restore Child.jsx
- addFile(
- 'Child.jsx',
- ` export default function Child() {
- return Child state 1
- }
- `,
- )
-
- // restore App.jsx
- editFile(
- 'App.jsx',
- (code) =>
- `import { useState } from 'react'
- import Child from './Child'
-
- function App() {
- return (
-
-
-
- )
- }
-
- export default App
- `,
- )
-
- await untilUpdated(() => page.textContent('p'), 'Child state 1')
- },
-)
diff --git a/playground/file-delete-restore/index.html b/playground/file-delete-restore/index.html
deleted file mode 100644
index 7417c442dfbf36..00000000000000
--- a/playground/file-delete-restore/index.html
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
diff --git a/playground/file-delete-restore/package.json b/playground/file-delete-restore/package.json
deleted file mode 100644
index ce3246877e945f..00000000000000
--- a/playground/file-delete-restore/package.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "name": "@vitejs/test-file-delete-restore",
- "private": true,
- "version": "0.0.0",
- "scripts": {
- "dev": "vite",
- "build": "vite build",
- "debug": "node --inspect-brk ../../packages/vite/bin/vite",
- "preview": "vite preview"
- },
- "dependencies": {
- "react": "^18.2.0",
- "react-dom": "^18.2.0"
- },
- "devDependencies": {
- "@vitejs/plugin-react": "^3.0.0-alpha.0"
- }
-}
diff --git a/playground/file-delete-restore/vite.config.js b/playground/file-delete-restore/vite.config.js
deleted file mode 100644
index d47f7cfc6704c5..00000000000000
--- a/playground/file-delete-restore/vite.config.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const react = require('@vitejs/plugin-react')
-
-/**
- * @type {import('vite').UserConfig}
- */
-module.exports = {
- plugins: [react()],
- build: {
- // to make tests faster
- minify: false,
- },
-}
diff --git a/playground/hmr/__tests__/hmr.spec.ts b/playground/hmr/__tests__/hmr.spec.ts
index c7f8b79d75fa5c..b6c786efefba54 100644
--- a/playground/hmr/__tests__/hmr.spec.ts
+++ b/playground/hmr/__tests__/hmr.spec.ts
@@ -1,10 +1,12 @@
import { beforeAll, describe, expect, it, test } from 'vitest'
import {
+ addFile,
browserLogs,
editFile,
getBg,
isBuild,
page,
+ removeFile,
untilBrowserLogAfter,
untilUpdated,
viteTestUrl,
@@ -713,4 +715,63 @@ if (!isBuild) {
await navigationPromise
}, /500/)
})
+
+ test('should hmr when file is deleted and restored', async () => {
+ await page.goto(viteTestUrl)
+
+ const parentFile = 'file-delete-restore/parent.js'
+ const childFile = 'file-delete-restore/child.js'
+
+ await untilUpdated(
+ () => page.textContent('.file-delete-restore'),
+ 'parent:child',
+ )
+
+ editFile(childFile, (code) =>
+ code.replace("value = 'child'", "value = 'child1'"),
+ )
+ await untilUpdated(
+ () => page.textContent('.file-delete-restore'),
+ 'parent:child1',
+ )
+
+ editFile(parentFile, (code) =>
+ code.replace(
+ "export { value as childValue } from './child'",
+ "export const childValue = 'not-child'",
+ ),
+ )
+ removeFile(childFile)
+ await untilUpdated(
+ () => page.textContent('.file-delete-restore'),
+ 'parent:not-child',
+ )
+
+ addFile(
+ childFile,
+ `
+import { rerender } from './runtime'
+
+export const value = 'child'
+
+if (import.meta.hot) {
+ import.meta.hot.accept((newMod) => {
+ if (!newMod) return
+
+ rerender({ child: newMod.value })
+ })
+}
+`,
+ )
+ editFile(parentFile, (code) =>
+ code.replace(
+ "export const childValue = 'not-child'",
+ "export { value as childValue } from './child'",
+ ),
+ )
+ await untilUpdated(
+ () => page.textContent('.file-delete-restore'),
+ 'parent:child',
+ )
+ })
}
diff --git a/playground/hmr/file-delete-restore/child.js b/playground/hmr/file-delete-restore/child.js
new file mode 100644
index 00000000000000..704c7d8c7e98cc
--- /dev/null
+++ b/playground/hmr/file-delete-restore/child.js
@@ -0,0 +1,11 @@
+import { rerender } from './runtime'
+
+export const value = 'child'
+
+if (import.meta.hot) {
+ import.meta.hot.accept((newMod) => {
+ if (!newMod) return
+
+ rerender({ child: newMod.value })
+ })
+}
diff --git a/playground/hmr/file-delete-restore/index.js b/playground/hmr/file-delete-restore/index.js
new file mode 100644
index 00000000000000..fa4908a32662ac
--- /dev/null
+++ b/playground/hmr/file-delete-restore/index.js
@@ -0,0 +1,4 @@
+import { render } from './runtime'
+import { childValue, parentValue } from './parent'
+
+render({ parent: parentValue, child: childValue })
diff --git a/playground/hmr/file-delete-restore/parent.js b/playground/hmr/file-delete-restore/parent.js
new file mode 100644
index 00000000000000..050bfa6d49b4c0
--- /dev/null
+++ b/playground/hmr/file-delete-restore/parent.js
@@ -0,0 +1,12 @@
+import { rerender } from './runtime'
+
+export const parentValue = 'parent'
+export { value as childValue } from './child'
+
+if (import.meta.hot) {
+ import.meta.hot.accept((newMod) => {
+ if (!newMod) return
+
+ rerender({ child: newMod.childValue, parent: newMod.parentValue })
+ })
+}
diff --git a/playground/hmr/file-delete-restore/runtime.js b/playground/hmr/file-delete-restore/runtime.js
new file mode 100644
index 00000000000000..c038eed173cdbf
--- /dev/null
+++ b/playground/hmr/file-delete-restore/runtime.js
@@ -0,0 +1,16 @@
+let state = {}
+
+export const render = (newState) => {
+ state = newState
+ apply()
+}
+
+export const rerender = (updates) => {
+ state = { ...state, ...updates }
+ apply()
+}
+
+const apply = () => {
+ document.querySelector('.file-delete-restore').textContent =
+ Object.values(state).join(':')
+}
diff --git a/playground/hmr/hmr.ts b/playground/hmr/hmr.ts
index 600685dce40a54..a9c1e332d529e3 100644
--- a/playground/hmr/hmr.ts
+++ b/playground/hmr/hmr.ts
@@ -3,6 +3,7 @@ import { virtual } from 'virtual:file'
import { foo as depFoo, nestedFoo } from './hmrDep'
import './importing-updated'
import './invalidation/parent'
+import './file-delete-restore'
export const foo = 1
text('.app', foo)
diff --git a/playground/hmr/index.html b/playground/hmr/index.html
index 3ddd29be711a67..9aadeaae6f3ff8 100644
--- a/playground/hmr/index.html
+++ b/playground/hmr/index.html
@@ -30,3 +30,4 @@
no
+
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index d5179f8b2c24ba..5b7c0cab2bf3ed 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -381,6 +381,9 @@ importers:
playground/css-codesplit-cjs:
specifiers: {}
+ playground/css-dynamic-import:
+ specifiers: {}
+
playground/css-sourcemap:
specifiers:
less: ^4.1.3
@@ -480,17 +483,6 @@ importers:
slash5: /slash/5.0.0
vue: 3.2.45
- playground/file-delete-restore:
- specifiers:
- '@vitejs/plugin-react': ^3.0.0-alpha.0
- react: ^18.2.0
- react-dom: ^18.2.0
- dependencies:
- react: 18.2.0
- react-dom: 18.2.0_react@18.2.0
- devDependencies:
- '@vitejs/plugin-react': 3.0.0-alpha.2
-
playground/fs-serve:
specifiers: {}
@@ -1455,50 +1447,6 @@ packages:
'@babel/helper-plugin-utils': 7.20.2
dev: true
- /@babel/plugin-transform-react-jsx-development/7.18.6_@babel+core@7.20.5:
- resolution: {integrity: sha512-SA6HEjwYFKF7WDjWcMcMGUimmw/nhNRDWxr+KaLSCrkD/LMDBvWRmHAYgE1HDeF8KUuI8OAu+RT6EOtKxSW2qA==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
- dependencies:
- '@babel/core': 7.20.5
- '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.20.5
- dev: true
-
- /@babel/plugin-transform-react-jsx-self/7.18.6_@babel+core@7.20.5:
- resolution: {integrity: sha512-A0LQGx4+4Jv7u/tWzoJF7alZwnBDQd6cGLh9P+Ttk4dpiL+J5p7NSNv/9tlEFFJDq3kjxOavWmbm6t0Gk+A3Ig==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
- dependencies:
- '@babel/core': 7.20.5
- '@babel/helper-plugin-utils': 7.20.2
- dev: true
-
- /@babel/plugin-transform-react-jsx-source/7.19.6_@babel+core@7.20.5:
- resolution: {integrity: sha512-RpAi004QyMNisst/pvSanoRdJ4q+jMCWyk9zdw/CyLB9j8RXEahodR6l2GyttDRyEVWZtbN+TpLiHJ3t34LbsQ==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
- dependencies:
- '@babel/core': 7.20.5
- '@babel/helper-plugin-utils': 7.20.2
- dev: true
-
- /@babel/plugin-transform-react-jsx/7.19.0_@babel+core@7.20.5:
- resolution: {integrity: sha512-UVEvX3tXie3Szm3emi1+G63jyw1w5IcMY0FSKM+CRnKRI5Mr1YbCNgsSTwoTwKphQEG9P+QqmuRFneJPZuHNhg==}
- engines: {node: '>=6.9.0'}
- peerDependencies:
- '@babel/core': ^7.0.0-0
- dependencies:
- '@babel/core': 7.20.5
- '@babel/helper-annotate-as-pure': 7.18.6
- '@babel/helper-module-imports': 7.18.6
- '@babel/helper-plugin-utils': 7.20.2
- '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.20.5
- '@babel/types': 7.20.5
- dev: true
-
/@babel/plugin-transform-typescript/7.20.2_@babel+core@7.20.5:
resolution: {integrity: sha512-jvS+ngBfrnTUBfOQq8NfGnSbF9BrqlR6hjJ2yVxMkmO5nL/cdifNbI30EfjRlN4g5wYWNnMPyj5Sa6R1pbLeag==}
engines: {node: '>=6.9.0'}
@@ -2388,23 +2336,6 @@ packages:
eslint-visitor-keys: 3.3.0
dev: true
- /@vitejs/plugin-react/3.0.0-alpha.2:
- resolution: {integrity: sha512-VObQvgDSWuEyxsCm/7gnMAzO82v7/JW1Yki6gvgFishqY4TMVHtm+3k7m6ci5zEBI22d+vfXh54mOpVHE+VgKA==}
- engines: {node: ^14.18.0 || >=16.0.0}
- peerDependencies:
- vite: ^3.0.0
- dependencies:
- '@babel/core': 7.20.5
- '@babel/plugin-transform-react-jsx': 7.19.0_@babel+core@7.20.5
- '@babel/plugin-transform-react-jsx-development': 7.18.6_@babel+core@7.20.5
- '@babel/plugin-transform-react-jsx-self': 7.18.6_@babel+core@7.20.5
- '@babel/plugin-transform-react-jsx-source': 7.19.6_@babel+core@7.20.5
- magic-string: 0.26.7
- react-refresh: 0.14.0
- transitivePeerDependencies:
- - supports-color
- dev: true
-
/@vitejs/plugin-vue-jsx/3.0.0-alpha.0:
resolution: {integrity: sha512-301Bbw+Ap+1EPYB/e8uDYAFAE/MNGb2TPf7zHLxVUagVkG9hkjFU4raUFucXtQ/cB8NkWBqcP66luS7rHgBCxQ==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -7146,11 +7077,6 @@ packages:
scheduler: 0.23.0
dev: false
- /react-refresh/0.14.0:
- resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==}
- engines: {node: '>=0.10.0'}
- dev: true
-
/react/18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}