Skip to content

Commit 2275c7d

Browse files
authored
fix: dev server should redirect when a page doesn't exist (#7841)
1 parent 3b42227 commit 2275c7d

2 files changed

Lines changed: 24 additions & 7 deletions

File tree

.changeset/plenty-bats-shake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Allow to return a redirect in dev mode when the original route is not present in the file system.

packages/astro/src/vite-plugin-astro-server/route.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { preload } from './index.js';
3131
import { getComponentMetadata } from './metadata.js';
3232
import { handle404Response, writeSSRResult, writeWebResponse } from './response.js';
3333
import { getScriptsForURL } from './scripts.js';
34+
import { isEndpointResult } from '../core/render/core.js';
3435

3536
const clientLocalsSymbol = Symbol.for('astro.locals');
3637

@@ -140,7 +141,7 @@ type HandleRoute = {
140141
incomingRequest: http.IncomingMessage;
141142
incomingResponse: http.ServerResponse;
142143
manifest: SSRManifest;
143-
status?: number;
144+
status?: 404 | 500;
144145
};
145146

146147
export async function handleRoute({
@@ -216,7 +217,7 @@ export async function handleRoute({
216217
const onRequest = options.middleware?.onRequest as MiddlewareResponseHandler | undefined;
217218

218219
const result = await tryRenderRoute(route.type, renderContext, env, mod, onRequest);
219-
if (route.type === 'endpoint' && !(result instanceof Response)) {
220+
if (isEndpointResult(result, route.type)) {
220221
if (result.type === 'response') {
221222
if (result.response.headers.get('X-Astro-Response') === 'Not-Found') {
222223
const fourOhFourRoute = await matchRoute('/404', env, manifestData);
@@ -254,7 +255,7 @@ export async function handleRoute({
254255
attachToResponse(response, result.cookies);
255256
await writeWebResponse(incomingResponse, response);
256257
}
257-
} else if (result instanceof Response) {
258+
} else {
258259
if (result.status === 404) {
259260
const fourOhFourRoute = await matchRoute('/404', env, manifestData);
260261
return handleRoute({
@@ -273,13 +274,24 @@ export async function handleRoute({
273274
}
274275

275276
let response = result;
276-
// Response.status is read-only, so a clone is required to override
277-
if (status && response.status !== status) {
277+
278+
if (
279+
// We are in a recursion, and it's possible that this function is called itself with a status code
280+
// By default, the status code passed via parameters is computed by the matched route.
281+
//
282+
// By default, we should give priority to the status code passed, although it's possible that
283+
// the `Response` emitted by the user is a redirect. If so, then return the returned response.
284+
response.status < 400 &&
285+
response.status >= 300
286+
) {
287+
await writeSSRResult(request, response, incomingResponse);
288+
return;
289+
} else if (status && response.status !== status && (status === 404 || status === 500)) {
290+
// Response.status is read-only, so a clone is required to override
278291
response = new Response(result.body, { ...result, status });
279292
}
280293
await writeSSRResult(request, response, incomingResponse);
281294
}
282-
// unreachable
283295
}
284296

285297
interface GetScriptsAndStylesParams {
@@ -360,7 +372,7 @@ async function getScriptsAndStyles({ env, filePath }: GetScriptsAndStylesParams)
360372
return { scripts, styles, links, metadata };
361373
}
362374

363-
function getStatus(matchedRoute?: MatchedRoute): number | undefined {
375+
function getStatus(matchedRoute?: MatchedRoute): 404 | 500 | undefined {
364376
if (!matchedRoute) return 404;
365377
if (matchedRoute.route.route === '/404') return 404;
366378
if (matchedRoute.route.route === '/500') return 500;

0 commit comments

Comments
 (0)