Skip to content

Commit 1c48ed2

Browse files
authored
Support Vite 5 (#9122)
1 parent cd08787 commit 1c48ed2

File tree

20 files changed

+657
-153
lines changed

20 files changed

+657
-153
lines changed

.changeset/light-ties-poke.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@astrojs/svelte': major
3+
'@astrojs/react': patch
4+
'@astrojs/vue': patch
5+
'astro': major
6+
---
7+
8+
Adds Vite 5 support. There are no breaking changes from Astro. Check the [Vite migration guide](https://vitejs.dev/guide/migration.html) for details of the breaking changes from Vite instead.

.changeset/wild-apricots-rescue.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@astrojs/svelte': major
3+
---
4+
5+
Drops support for Svelte 3 as `@sveltejs/vite-plugin-svelte` is updated to `3.0.0` which does not support Svelte 3

packages/astro/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@
175175
"tsconfck": "^3.0.0",
176176
"unist-util-visit": "^4.1.2",
177177
"vfile": "^5.3.7",
178-
"vite": "^4.4.9",
178+
"vite": "^5.0.0",
179179
"vitefu": "^0.2.4",
180180
"which-pm": "^2.1.1",
181181
"yargs-parser": "^21.1.1",
@@ -222,7 +222,7 @@
222222
"rehype-slug": "^5.0.1",
223223
"rehype-toc": "^3.0.2",
224224
"remark-code-titles": "^0.1.2",
225-
"rollup": "^3.28.1",
225+
"rollup": "^4.4.1",
226226
"sass": "^1.66.1",
227227
"srcset-parse": "^1.1.0",
228228
"unified": "^10.1.2"

packages/astro/src/core/preview/static-preview-server.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,6 @@ export default async function createStaticPreviewServer(
7272
host: getResolvedHostForHttpServer(settings.config.server.host),
7373
port: settings.config.server.port,
7474
closed,
75-
// In Vite 5, `httpServer` may be a `Http2SecureServer`, but we know we are only starting a HTTP server
76-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
7775
server: previewServer.httpServer as http.Server,
7876
stop: async () => {
7977
await new Promise((resolve, reject) => {

packages/astro/src/core/preview/vite-plugin-astro-preview.ts

Lines changed: 43 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import fs from 'node:fs';
2+
import type { IncomingMessage, ServerResponse } from 'node:http';
23
import { fileURLToPath } from 'node:url';
34
import type { Connect, Plugin } from 'vite';
4-
import { version } from 'vite';
55
import type { AstroSettings } from '../../@types/astro.js';
66
import { notFoundTemplate, subpathNotUsedTemplate } from '../../template/4xx.js';
7+
import { cleanUrl } from '../../vite-plugin-utils/index.js';
78
import { stripBase } from './util.js';
89

910
const HAS_FILE_EXTENSION_REGEXP = /^.*\.[^\\]+$/;
10-
const IS_VITE_5 = version.startsWith('5.');
1111

1212
export function vitePluginAstroPreview(settings: AstroSettings): Plugin {
1313
const { base, outDir, trailingSlash } = settings.config;
@@ -24,8 +24,7 @@ export function vitePluginAstroPreview(settings: AstroSettings): Plugin {
2424
return;
2525
}
2626

27-
const strippedPathname = stripBase(req.url!, base);
28-
const pathname = new URL(strippedPathname, 'https://a.b').pathname;
27+
const pathname = cleanUrl(stripBase(req.url!, base));
2928
const isRoot = pathname === '/';
3029

3130
// Validate trailingSlash
@@ -53,29 +52,49 @@ export function vitePluginAstroPreview(settings: AstroSettings): Plugin {
5352
});
5453

5554
return () => {
56-
const fourOhFourMiddleware: Connect.NextHandleFunction = (req, res) => {
57-
const errorPagePath = fileURLToPath(outDir + '/404.html');
58-
if (fs.existsSync(errorPagePath)) {
59-
res.statusCode = 404;
60-
res.setHeader('Content-Type', 'text/html;charset=utf-8');
61-
res.end(fs.readFileSync(errorPagePath));
62-
} else {
63-
const pathname = stripBase(req.url!, base);
64-
res.statusCode = 404;
65-
res.end(notFoundTemplate(pathname, 'Not Found'));
66-
}
67-
};
55+
// NOTE: the `base` is stripped from `req.url` for post middlewares
6856

69-
// Vite 5 has its own 404 middleware, we replace it with ours instead.
70-
if (IS_VITE_5) {
71-
for (const middleware of server.middlewares.stack) {
72-
// This hardcoded name will not break between Vite versions
73-
if ((middleware.handle as Connect.HandleFunction).name === 'vite404Middleware') {
74-
middleware.handle = fourOhFourMiddleware;
57+
server.middlewares.use((req, res, next) => {
58+
const pathname = cleanUrl(req.url!);
59+
60+
// Vite doesn't handle /foo/ if /foo.html exists, we handle it anyways
61+
if (pathname.endsWith('/')) {
62+
const pathnameWithoutSlash = pathname.slice(0, -1);
63+
const htmlPath = fileURLToPath(outDir + pathnameWithoutSlash + '.html');
64+
if (fs.existsSync(htmlPath)) {
65+
req.url = pathnameWithoutSlash + '.html';
66+
return next();
7567
}
7668
}
77-
} else {
78-
server.middlewares.use(fourOhFourMiddleware);
69+
// Vite doesn't handle /foo if /foo/index.html exists, we handle it anyways
70+
else {
71+
const htmlPath = fileURLToPath(outDir + pathname + '/index.html');
72+
if (fs.existsSync(htmlPath)) {
73+
req.url = pathname + '/index.html';
74+
return next();
75+
}
76+
}
77+
78+
next();
79+
});
80+
81+
// Vite has its own 404 middleware, we replace it with ours instead.
82+
for (const middleware of server.middlewares.stack) {
83+
// This hardcoded name will not break between Vite versions
84+
if ((middleware.handle as Connect.HandleFunction).name === 'vite404Middleware') {
85+
// Fallback to 404 page if it exists
86+
middleware.handle = (req: IncomingMessage, res: ServerResponse) => {
87+
const errorPagePath = fileURLToPath(outDir + '/404.html');
88+
if (fs.existsSync(errorPagePath)) {
89+
res.statusCode = 404;
90+
res.setHeader('Content-Type', 'text/html;charset=utf-8');
91+
res.end(fs.readFileSync(errorPagePath));
92+
} else {
93+
res.statusCode = 404;
94+
res.end(notFoundTemplate(req.url!, 'Not Found'));
95+
}
96+
};
97+
}
7998
}
8099
};
81100
},

packages/astro/src/vite-plugin-load-fallback/index.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import nodeFs from 'node:fs';
22
import npath from 'node:path';
33
import type * as vite from 'vite';
44
import { slash } from '../core/path.js';
5+
import { cleanUrl } from '../vite-plugin-utils/index.js';
56

67
type NodeFileSystemModule = typeof nodeFs;
78

@@ -77,8 +78,3 @@ export default function loadFallbackPlugin({
7778
},
7879
];
7980
}
80-
81-
const queryRE = /\?.*$/s;
82-
const hashRE = /#.*$/s;
83-
84-
const cleanUrl = (url: string): string => url.replace(hashRE, '').replace(queryRE, '');

packages/astro/src/vite-plugin-scripts/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ export default function astroScriptsPlugin({ settings }: { settings: AstroSettin
5050
},
5151
buildStart() {
5252
const hasHydrationScripts = settings.scripts.some((s) => s.stage === 'before-hydration');
53-
// @ts-expect-error Vite 5 renamed `ssrBuild` to `isSsrBuild`
54-
const isSsrBuild = env?.ssrBuild || env?.isSsrBuild;
53+
const isSsrBuild = env?.isSsrBuild;
5554
if (hasHydrationScripts && env?.command === 'build' && !isSsrBuild) {
5655
this.emitFile({
5756
type: 'chunk',

packages/astro/src/vite-plugin-utils/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,8 @@ export function normalizeFilename(filename: string, root: URL) {
5656
}
5757
return removeLeadingForwardSlashWindows(filename);
5858
}
59+
60+
const postfixRE = /[?#].*$/s;
61+
export function cleanUrl(url: string): string {
62+
return url.replace(postfixRE, '');
63+
}

packages/astro/test/fixtures/integration-add-page-extension/astro.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineConfig } from 'rollup'
1+
import { defineConfig } from 'astro/config'
22
import test from './integration.js'
33

44
export default defineConfig({

packages/astro/test/fixtures/integration-server-setup/astro.config.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { defineConfig } from 'rollup'
1+
import { defineConfig } from 'astro/config'
22
import test from './integration.js'
33

44
export default defineConfig({

0 commit comments

Comments
 (0)