From 23e5f980eab03eeb7f6ad505347e64cb9194eaa9 Mon Sep 17 00:00:00 2001 From: Daniel Roe Date: Wed, 25 Jan 2023 04:24:58 -0800 Subject: [PATCH] fix(vite): ensure newly created pages do not return 404 (#18447) Co-authored-by: Anthony Fu --- package.json | 2 +- packages/test-utils/package.json | 2 +- packages/vite/package.json | 2 +- packages/vite/src/vite-node.ts | 41 +++++++--- pnpm-lock.yaml | 136 +++++++------------------------ test/basic.test.ts | 14 ++++ 6 files changed, 77 insertions(+), 120 deletions(-) diff --git a/package.json b/package.json index 7f857f57f1..f545567cf2 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,7 @@ "ufo": "^1.0.1", "unbuild": "^1.1.1", "vite": "^4.0.4", - "vitest": "^0.27.2", + "vitest": "^0.28.2", "vue-tsc": "^1.0.24" }, "packageManager": "pnpm@7.25.1", diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json index 0ebb5e4e60..34191e99ab 100644 --- a/packages/test-utils/package.json +++ b/packages/test-utils/package.json @@ -26,7 +26,7 @@ "devDependencies": { "playwright": "^1.29.2", "unbuild": "latest", - "vitest": "^0.27.2" + "vitest": "^0.28.2" }, "peerDependencies": { "vue": "^3.2.45" diff --git a/packages/vite/package.json b/packages/vite/package.json index 31709d3f70..f2c3d20f42 100644 --- a/packages/vite/package.json +++ b/packages/vite/package.json @@ -49,7 +49,7 @@ "ufo": "^1.0.1", "unplugin": "^1.0.1", "vite": "~4.0.4", - "vite-node": "^0.27.2", + "vite-node": "^0.28.2", "vite-plugin-checker": "^0.5.4", "vue-bundle-renderer": "^1.0.0" }, diff --git a/packages/vite/src/vite-node.ts b/packages/vite/src/vite-node.ts index ad9c6f8f2f..534f508550 100644 --- a/packages/vite/src/vite-node.ts +++ b/packages/vite/src/vite-node.ts @@ -18,12 +18,18 @@ import { transpile } from './utils/transpile' export function viteNodePlugin (ctx: ViteBuildContext): VitePlugin { // Store the invalidates for the next rendering const invalidates = new Set() + function markInvalidate (mod: ModuleNode) { if (!mod.id) { return } if (invalidates.has(mod.id)) { return } invalidates.add(mod.id) - for (const importer of mod.importers) { - markInvalidate(importer) + markInvalidates(mod.importers) + } + + function markInvalidates (mods?: ModuleNode[] | Set) { + if (!mods) { return } + for (const mod of mods) { + markInvalidate(mod) } } @@ -31,21 +37,34 @@ export function viteNodePlugin (ctx: ViteBuildContext): VitePlugin { name: 'nuxt:vite-node-server', enforce: 'post', configureServer (server) { - server.middlewares.use('/__nuxt_vite_node__', toNodeListener(createViteNodeApp(ctx, invalidates))) - // Invalidate all virtual modules when templates are regenerated - ctx.nuxt.hook('app:templatesGenerated', () => { + function invalidateVirtualModules () { for (const [id, mod] of server.moduleGraph.idToModuleMap) { if (id.startsWith('virtual:')) { markInvalidate(mod) } } - }) - }, - handleHotUpdate ({ file, server }) { - const mods = server.moduleGraph.getModulesByFile(file) || [] - for (const mod of mods) { - markInvalidate(mod) + for (const plugin of ctx.nuxt.options.plugins) { + markInvalidates(server.moduleGraph.getModulesByFile(typeof plugin === 'string' ? plugin : plugin.src)) + } + for (const template of ctx.nuxt.options.build.templates) { + markInvalidates(server.moduleGraph.getModulesByFile(template?.src)) + } } + + server.middlewares.use('/__nuxt_vite_node__', toNodeListener(createViteNodeApp(ctx, invalidates))) + + // Invalidate all virtual modules when templates are regenerated + ctx.nuxt.hook('app:templatesGenerated', () => { + invalidateVirtualModules() + }) + + server.watcher.on('all', (event, file) => { + markInvalidates(server.moduleGraph.getModulesByFile(file)) + // Invalidate all virtual modules when a file is added or removed + if (event === 'add' || event === 'unlink') { + invalidateVirtualModules() + } + }) } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 089cf6bcfa..8d81b3d388 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,7 +50,7 @@ importers: ufo: ^1.0.1 unbuild: ^1.1.1 vite: ^4.0.4 - vitest: ^0.27.2 + vitest: ^0.28.2 vue-tsc: ^1.0.24 devDependencies: '@actions/core': 1.10.0 @@ -86,7 +86,7 @@ importers: ufo: 1.0.1 unbuild: 1.1.1 vite: 4.0.4_@types+node@18.11.18 - vitest: 0.27.3 + vitest: 0.28.2 vue-tsc: 1.0.24_typescript@4.9.4 examples/advanced/config-extends: @@ -121,7 +121,7 @@ importers: devDependencies: '@nuxt/test-utils': link:../../../packages/test-utils nuxt: link:../../../packages/nuxt - vitest: 0.28.1 + vitest: 0.28.2 examples/app-config: specifiers: @@ -566,7 +566,7 @@ importers: pathe: ^1.0.0 playwright: ^1.29.2 unbuild: ^1.1.1 - vitest: ^0.27.2 + vitest: ^0.28.2 dependencies: '@nuxt/kit': link:../kit '@nuxt/schema': link:../schema @@ -580,7 +580,7 @@ importers: devDependencies: playwright: 1.29.2 unbuild: 1.1.1 - vitest: 0.27.3 + vitest: 0.28.2 packages/vite: specifiers: @@ -617,7 +617,7 @@ importers: unbuild: ^1.1.1 unplugin: ^1.0.1 vite: ^4.0.4 - vite-node: ^0.27.2 + vite-node: ^0.28.2 vite-plugin-checker: ^0.5.4 vue: 3.2.45 vue-bundle-renderer: ^1.0.0 @@ -652,7 +652,7 @@ importers: ufo: 1.0.1 unplugin: 1.0.1 vite: 4.0.4 - vite-node: 0.27.3 + vite-node: 0.28.2 vite-plugin-checker: 0.5.4_vite@4.0.4 vue-bundle-renderer: 1.0.0 devDependencies: @@ -2575,30 +2575,30 @@ packages: vue: 3.2.45 dev: false - /@vitest/expect/0.28.1: - resolution: {integrity: sha512-BOvWjBoocKrrTTTC0opIvzOEa7WR/Ovx4++QYlbjYKjnQJfWRSEQkTpAIEfOURtZ/ICcaLk5jvsRshXvjarZew==} + /@vitest/expect/0.28.2: + resolution: {integrity: sha512-syEAK7I24/aGR2lXma98WNnvMwAJ+fMx32yPcj8eLdCEWjZI3SH8ozMaKQMy65B/xZCZAl6MXmfjtJb2CpWPMg==} dependencies: - '@vitest/spy': 0.28.1 - '@vitest/utils': 0.28.1 + '@vitest/spy': 0.28.2 + '@vitest/utils': 0.28.2 chai: 4.3.7 dev: true - /@vitest/runner/0.28.1: - resolution: {integrity: sha512-kOdmgiNe+mAxZhvj2eUTqKnjfvzzknmrcS+SZXV7j6VgJuWPFAMCv3TWOe03nF9dkqDfVLCDRw/hwFuCzmzlQg==} + /@vitest/runner/0.28.2: + resolution: {integrity: sha512-BJ9CtfPwWM8uc5p7Ty0OprwApyh8RIaSK7QeQPhwfDYA59AAE009OytqA3aX0yj1Qy5+k/mYFJS8RJZgsueSGA==} dependencies: - '@vitest/utils': 0.28.1 + '@vitest/utils': 0.28.2 p-limit: 4.0.0 pathe: 1.1.0 dev: true - /@vitest/spy/0.28.1: - resolution: {integrity: sha512-XGlD78cG3IxXNnGwEF121l0MfTNlHSdI25gS2ik0z6f/D9wWUOru849QkJbuNl4CMlZCtNkx3b5IS6MRwKGKuA==} + /@vitest/spy/0.28.2: + resolution: {integrity: sha512-KlLzTzi5E6tHcI12VT+brlY1Pdi7sUzLf9+YXgh80+CfLu9DqPZi38doBBAUhqEnW/emoLCMinPMMoJlNAQZXA==} dependencies: tinyspy: 1.0.2 dev: true - /@vitest/utils/0.28.1: - resolution: {integrity: sha512-a7cV1fs5MeU+W+8sn8gM9gV+q7V/wYz3/4y016w/icyJEKm9AMdSHnrzxTWaElJ07X40pwU6m5353Jlw6Rbd8w==} + /@vitest/utils/0.28.2: + resolution: {integrity: sha512-wcVTNnVdr22IGxZHDgiXrxWYcXsNg0iX2iBuOH3tVs9eme6fXJ0wxjn0/gCpp0TofQSoUwo3tX8LNACFVseDuA==} dependencies: cli-truncate: 3.1.0 diff: 5.1.0 @@ -6665,9 +6665,6 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} - /pathe/0.2.0: - resolution: {integrity: sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==} - /pathe/0.3.9: resolution: {integrity: sha512-6Y6s0vT112P3jD8dGfuS6r+lpa0qqNrLyHPOwvXMnyNTQaYiwgau2DP3aNDsR13xqtGj7rrPo+jFUATpU6/s+g==} dev: true @@ -8381,15 +8378,15 @@ packages: extsprintf: 1.3.0 dev: true - /vite-node/0.27.3: - resolution: {integrity: sha512-eyJYOO64o5HIp8poc4bJX+ZNBwMZeI3f6/JdiUmJgW02Mt7LnoCtDMRVmLaY9S05SIsjGe339ZK4uo2wQ+bF9g==} + /vite-node/0.28.2: + resolution: {integrity: sha512-zyiJ3DLs9zXign4P2MD4PQk+7rdT+JkHukgmmS0KuImbCQ7WnCdea5imQVeT6OtUsBwsLztJxQODUsinVr91tg==} engines: {node: '>=v14.16.0'} hasBin: true dependencies: cac: 6.7.14 debug: 4.3.4 mlly: 1.1.0 - pathe: 0.2.0 + pathe: 1.1.0 picocolors: 1.0.0 source-map: 0.6.1 source-map-support: 0.5.21 @@ -8404,31 +8401,8 @@ packages: - terser dev: false - /vite-node/0.27.3_@types+node@18.11.18: - resolution: {integrity: sha512-eyJYOO64o5HIp8poc4bJX+ZNBwMZeI3f6/JdiUmJgW02Mt7LnoCtDMRVmLaY9S05SIsjGe339ZK4uo2wQ+bF9g==} - engines: {node: '>=v14.16.0'} - hasBin: true - dependencies: - cac: 6.7.14 - debug: 4.3.4 - mlly: 1.1.0 - pathe: 0.2.0 - picocolors: 1.0.0 - source-map: 0.6.1 - source-map-support: 0.5.21 - vite: 4.0.4_@types+node@18.11.18 - transitivePeerDependencies: - - '@types/node' - - less - - sass - - stylus - - sugarss - - supports-color - - terser - dev: true - - /vite-node/0.28.1_@types+node@18.11.18: - resolution: {integrity: sha512-Mmab+cIeElkVn4noScCRjy8nnQdh5LDIR4QCH/pVWtY15zv5Z1J7u6/471B9JZ2r8CEIs42vTbngaamOVkhPLA==} + /vite-node/0.28.2_@types+node@18.11.18: + resolution: {integrity: sha512-zyiJ3DLs9zXign4P2MD4PQk+7rdT+JkHukgmmS0KuImbCQ7WnCdea5imQVeT6OtUsBwsLztJxQODUsinVr91tg==} engines: {node: '>=v14.16.0'} hasBin: true dependencies: @@ -8565,8 +8539,8 @@ packages: fsevents: 2.3.2 dev: true - /vitest/0.27.3: - resolution: {integrity: sha512-Ld3UVgRVhJUtqvQ3dW89GxiApFAgBsWJZBCWzK+gA3w2yG68csXlGZZ4WDJURf+8ecNfgrScga6xY+8YSOpiMg==} + /vitest/0.28.2: + resolution: {integrity: sha512-HJBlRla4Mng0OiZ8aWunCecJ6BzLDA4yuzuxiBuBU2MXjGB6I4zT7QgIBL/UrwGKlNxLwaDC5P/4OpeuTlW8yQ==} engines: {node: '>=v14.16.0'} hasBin: true peerDependencies: @@ -8590,60 +8564,10 @@ packages: '@types/chai': 4.3.4 '@types/chai-subset': 1.3.3 '@types/node': 18.11.18 - acorn: 8.8.2 - acorn-walk: 8.2.0 - cac: 6.7.14 - chai: 4.3.7 - debug: 4.3.4 - local-pkg: 0.4.3 - picocolors: 1.0.0 - source-map: 0.6.1 - std-env: 3.3.1 - strip-literal: 1.0.0 - tinybench: 2.3.1 - tinypool: 0.3.0 - tinyspy: 1.0.2 - vite: 4.0.4_@types+node@18.11.18 - vite-node: 0.27.3_@types+node@18.11.18 - why-is-node-running: 2.2.2 - transitivePeerDependencies: - - less - - sass - - stylus - - sugarss - - supports-color - - terser - dev: true - - /vitest/0.28.1: - resolution: {integrity: sha512-F6wAO3K5+UqJCCGt0YAl3Ila2f+fpBrJhl9n7qWEhREwfzQeXlMkkCqGqGtzBxCSa8kv5QHrkshX8AaPTXYACQ==} - engines: {node: '>=v14.16.0'} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@vitest/browser': '*' - '@vitest/ui': '*' - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - dependencies: - '@types/chai': 4.3.4 - '@types/chai-subset': 1.3.3 - '@types/node': 18.11.18 - '@vitest/expect': 0.28.1 - '@vitest/runner': 0.28.1 - '@vitest/spy': 0.28.1 - '@vitest/utils': 0.28.1 + '@vitest/expect': 0.28.2 + '@vitest/runner': 0.28.2 + '@vitest/spy': 0.28.2 + '@vitest/utils': 0.28.2 acorn: 8.8.2 acorn-walk: 8.2.0 cac: 6.7.14 @@ -8659,7 +8583,7 @@ packages: tinypool: 0.3.0 tinyspy: 1.0.2 vite: 4.0.4_@types+node@18.11.18 - vite-node: 0.28.1_@types+node@18.11.18 + vite-node: 0.28.2_@types+node@18.11.18 why-is-node-running: 2.2.2 transitivePeerDependencies: - less diff --git a/test/basic.test.ts b/test/basic.test.ts index e8a5f7c20a..150b347a37 100644 --- a/test/basic.test.ts +++ b/test/basic.test.ts @@ -1029,5 +1029,19 @@ if (isDev() && !isWindows) { expect(consoleLogErrors).toEqual([]) expect(consoleLogWarnings).toEqual([]) }, 60_000) + + it('should detect new routes', async () => { + const html = await $fetch('/some-404') + expect(html).toContain('404 at some-404') + + // write new page route + const indexVue = await fsp.readFile(join(fixturePath, 'pages/index.vue'), 'utf8') + await fsp.writeFile(join(fixturePath, 'pages/some-404.vue'), indexVue) + + await expectWithPolling( + () => $fetch('/some-404').then(r => r.includes('Hello Nuxt 3') ? 'ok' : 'fail'), + 'ok' + ) + }) }) }