diff --git a/.changeset/olive-feet-eat.md b/.changeset/olive-feet-eat.md new file mode 100644 index 000000000000..6984b29563b7 --- /dev/null +++ b/.changeset/olive-feet-eat.md @@ -0,0 +1,9 @@ +--- +'astro': patch +--- + +Improves the developer experience of the custom `500.astro` page in development mode. + +Before, in development, an error thrown during the rendering phase would display the default error overlay, even when users had the `500.astro` page. + +Now, the development server will display the `500.astro` and the original error is logged in the console. diff --git a/packages/astro/src/core/constants.ts b/packages/astro/src/core/constants.ts index a4d32abe503c..0930ea6f0f7d 100644 --- a/packages/astro/src/core/constants.ts +++ b/packages/astro/src/core/constants.ts @@ -32,6 +32,11 @@ export const ROUTE_TYPE_HEADER = 'X-Astro-Route-Type'; */ export const DEFAULT_404_COMPONENT = 'astro-default-404.astro'; +/** + * The value of the `component` field of the default 500 page, which is used when there is no user-provided 404.astro page. + */ +export const DEFAULT_500_COMPONENT = 'astro-default-500.astro'; + /** * A response with one of these status codes will be rewritten * with the result of rendering the respective error page. diff --git a/packages/astro/src/core/routing/astro-designed-error-pages.ts b/packages/astro/src/core/routing/astro-designed-error-pages.ts index 6a047f6d55d9..f6785cbdcb00 100644 --- a/packages/astro/src/core/routing/astro-designed-error-pages.ts +++ b/packages/astro/src/core/routing/astro-designed-error-pages.ts @@ -1,6 +1,6 @@ import type { ManifestData, RouteData } from '../../@types/astro.js'; import notFoundTemplate from '../../template/4xx.js'; -import { DEFAULT_404_COMPONENT } from '../constants.js'; +import { DEFAULT_404_COMPONENT, DEFAULT_500_COMPONENT } from '../constants.js'; export const DEFAULT_404_ROUTE: RouteData = { component: DEFAULT_404_COMPONENT, @@ -16,6 +16,20 @@ export const DEFAULT_404_ROUTE: RouteData = { isIndex: false, }; +export const DEFAULT_500_ROUTE: RouteData = { + component: DEFAULT_500_COMPONENT, + generate: () => '', + params: [], + pattern: /\/500/, + prerender: false, + pathname: '/500', + segments: [[{ content: '500', dynamic: false, spread: false }]], + type: 'page', + route: '/500', + fallbackRoutes: [], + isIndex: false, +}; + export function ensure404Route(manifest: ManifestData) { if (!manifest.routes.some((route) => route.route === '/404')) { manifest.routes.push(DEFAULT_404_ROUTE); diff --git a/packages/astro/src/vite-plugin-astro-server/route.ts b/packages/astro/src/vite-plugin-astro-server/route.ts index b451a8ff6395..b05412314309 100644 --- a/packages/astro/src/vite-plugin-astro-server/route.ts +++ b/packages/astro/src/vite-plugin-astro-server/route.ts @@ -41,6 +41,11 @@ function getCustom404Route(manifestData: ManifestData): RouteData | undefined { return manifestData.routes.find((r) => route404.test(r.route)); } +function getCustom500Route(manifestData: ManifestData): RouteData | undefined { + const route500 = /^\/500\/?$/; + return manifestData.routes.find((r) => route500.test(r.route)); +} + export async function matchRoute( pathname: string, manifestData: ManifestData, @@ -273,7 +278,22 @@ export async function handleRoute({ }); } - let response = await renderContext.render(mod); + let response; + try { + response = await renderContext.render(mod); + } catch (err: any) { + const custom500 = getCustom500Route(manifestData); + if (!custom500) { + throw err; + } + // Log useful information that the custom 500 page may not display unlike the default error overlay + logger.error('router', err.stack || err.message); + const filePath = new URL(`./${custom500.component}`, config.root); + const preloadedComponent = await pipeline.preload(custom500, filePath); + response = await renderContext.render(preloadedComponent); + status = 500; + } + if (isLoggedRequest(pathname)) { const timeEnd = performance.now(); logger.info( @@ -321,6 +341,7 @@ export async function handleRoute({ await writeSSRResult(request, response, incomingResponse); return; } + // Apply the `status` override to the response object before responding. // Response.status is read-only, so a clone is required to override. if (status && response.status !== status && (status === 404 || status === 500)) { diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js index 17c08db21ed2..a4fd13fcbdcb 100644 --- a/packages/astro/test/core-image.test.js +++ b/packages/astro/test/core-image.test.js @@ -712,7 +712,7 @@ describe('astro:image', () => { let res = await fixture.fetch('/get-image-empty'); await res.text(); - assert.equal(logs.length, 1); + assert.equal(logs.length >= 1, true); assert.equal(logs[0].message.includes('Expected getImage() parameter'), true); }); @@ -721,7 +721,7 @@ describe('astro:image', () => { let res = await fixture.fetch('/get-image-undefined'); await res.text(); - assert.equal(logs.length, 1); + assert.equal(logs.length >= 1, true); assert.equal(logs[0].message.includes('Expected `src` property'), true); }); diff --git a/packages/astro/test/fixtures/rewrite-runtime-error-custom500/astro.config.mjs b/packages/astro/test/fixtures/rewrite-runtime-error-custom500/astro.config.mjs new file mode 100644 index 000000000000..af13ef19b477 --- /dev/null +++ b/packages/astro/test/fixtures/rewrite-runtime-error-custom500/astro.config.mjs @@ -0,0 +1,9 @@ +import { defineConfig } from 'astro/config'; + +// https://astro.build/config +export default defineConfig({ + experimental: { + rewriting: true + }, + site: "https://example.com" +}); diff --git a/packages/astro/test/fixtures/rewrite-runtime-error-custom500/package.json b/packages/astro/test/fixtures/rewrite-runtime-error-custom500/package.json new file mode 100644 index 000000000000..6d844adc4e14 --- /dev/null +++ b/packages/astro/test/fixtures/rewrite-runtime-error-custom500/package.json @@ -0,0 +1,8 @@ +{ + "name": "@test/rewrite-runtime-errror-custom500", + "version": "0.0.0", + "private": true, + "dependencies": { + "astro": "workspace:*" + } +} diff --git a/packages/astro/test/fixtures/rewrite-runtime-error-custom500/src/pages/500.astro b/packages/astro/test/fixtures/rewrite-runtime-error-custom500/src/pages/500.astro new file mode 100644 index 000000000000..7df3fc458c43 --- /dev/null +++ b/packages/astro/test/fixtures/rewrite-runtime-error-custom500/src/pages/500.astro @@ -0,0 +1,4 @@ +--- +--- + +