diff --git a/.changeset/hot-dingos-dress.md b/.changeset/hot-dingos-dress.md new file mode 100644 index 0000000000000..c3d59944c12b4 --- /dev/null +++ b/.changeset/hot-dingos-dress.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fixes an issue where `i18n` is enabled, Astro couldn't render the `404.astro` component when navigating non-existent routes. diff --git a/packages/astro/src/i18n/middleware.ts b/packages/astro/src/i18n/middleware.ts index 097332805759a..f4649dce2d32a 100644 --- a/packages/astro/src/i18n/middleware.ts +++ b/packages/astro/src/i18n/middleware.ts @@ -1,6 +1,6 @@ import type { APIContext, MiddlewareHandler, SSRManifest } from '../@types/astro.js'; import type { SSRManifestI18n } from '../core/app/types.js'; -import { ROUTE_TYPE_HEADER } from '../core/constants.js'; +import { REROUTE_DIRECTIVE_HEADER, ROUTE_TYPE_HEADER } from '../core/constants.js'; import { type MiddlewarePayload, normalizeTheLocale, @@ -65,6 +65,12 @@ export function createI18nMiddleware( return async (context, next) => { const response = await next(); const type = response.headers.get(ROUTE_TYPE_HEADER); + + // This is case where we are internally rendering a 404/500, so we need to bypass checks that were done already + const isReroute = response.headers.get(REROUTE_DIRECTIVE_HEADER); + if (isReroute === 'no' && typeof i18n.fallback === 'undefined') { + return response; + } // If the route we're processing is not a page, then we ignore it if (type !== 'page' && type !== 'fallback') { return response; diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index 8de52d158bb03..837e2ef089381 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -127,7 +127,6 @@ type HandleRoute = { url: URL; pathname: string; body: ArrayBuffer | undefined; - origin: string; manifestData: ManifestData; incomingRequest: http.IncomingMessage; incomingResponse: http.ServerResponse; @@ -139,7 +138,6 @@ export async function handleRoute({ url, pathname, body, - origin, pipeline, manifestData, incomingRequest, @@ -156,7 +154,6 @@ export async function handleRoute({ let request: Request; let renderContext: RenderContext; let mod: ComponentInstance | undefined = undefined; - let options: SSROptions | undefined = undefined; let route: RouteData; const middleware = (await loadMiddleware(loader)).onRequest; const locals = Reflect.get(incomingRequest, clientLocalsSymbol); @@ -181,15 +178,6 @@ export async function handleRoute({ if (value) incomingResponse.setHeader(name, value); } - options = { - pipeline, - filePath, - preload: preloadedComponent, - pathname, - request, - route, - }; - mod = preloadedComponent; renderContext = await RenderContext.create({ @@ -248,18 +236,17 @@ export async function handleRoute({ if (statusCode === 404 && response.headers.get(REROUTE_DIRECTIVE_HEADER) !== 'no') { const fourOhFourRoute = await matchRoute('/404', manifestData, pipeline); - if (options && options.route !== fourOhFourRoute?.route) - return handleRoute({ - ...options, - matchedRoute: fourOhFourRoute, - url: new URL(pathname, url), - body, - origin, + if (fourOhFourRoute) { + renderContext = await RenderContext.create({ + locals, pipeline, - manifestData, - incomingRequest, - incomingResponse, + pathname, + middleware: isDefaultPrerendered404(fourOhFourRoute.route) ? undefined : middleware, + request, + routeData: fourOhFourRoute.route, }); + response = await renderContext.render(fourOhFourRoute.preloadedComponent); + } } // We remove the internally-used header before we send the response to the user agent. diff --git a/packages/astro/test/fixtures/i18n-routing/src/pages/404.astro b/packages/astro/test/fixtures/i18n-routing/src/pages/404.astro index fce4a30b836c4..bfde753739fef 100644 --- a/packages/astro/test/fixtures/i18n-routing/src/pages/404.astro +++ b/packages/astro/test/fixtures/i18n-routing/src/pages/404.astro @@ -7,6 +7,7 @@ const currentLocale = Astro.currentLocale;
Current Locale: {currentLocale ? currentLocale : "none"}