(
return await ctx.next();
} catch (err) {
ctx.error = err;
+
+ if (err instanceof HttpError) {
+ if (err.status >= 500) {
+ if (DENO_DEPLOYMENT_ID === undefined) {
+ const codeFrame = getCodeFrameFromError(err, ctx.config.root);
+ if (codeFrame !== undefined) {
+ console.error(codeFrame);
+ }
+ }
+ console.error(err);
+ }
+ } else {
+ if (DENO_DEPLOYMENT_ID === undefined) {
+ const codeFrame = getCodeFrameFromError(err, ctx.config.root);
+ if (codeFrame !== undefined) {
+ console.error(codeFrame);
+ }
+ }
+ console.error(err);
+ }
+
return mid(ctx);
}
};
diff --git a/src/plugins/fs_routes/mod_test.tsx b/src/plugins/fs_routes/mod_test.tsx
index 262e377ba54..693b2aa6361 100644
--- a/src/plugins/fs_routes/mod_test.tsx
+++ b/src/plugins/fs_routes/mod_test.tsx
@@ -941,6 +941,74 @@ Deno.test("fsRoutes - async route components returning response", async () => {
expect(text).toEqual("index");
});
+Deno.test(
+ "fsRoutes - returns response code from error route",
+ async () => {
+ const server = await createServer<{ text: string }>({
+ "routes/_app.tsx": {
+ default: (ctx) => {
+ return (
+
+ _app/
+
+ );
+ },
+ },
+ "routes/_error.tsx": {
+ default: () => fail
,
+ },
+ "routes/index.tsx": {
+ default: () => index
,
+ },
+ "routes/bar.tsx": {
+ default: () => index
,
+ },
+ "routes/foo/index.tsx": {
+ default: () => foo/index
,
+ },
+ "routes/foo/_error.tsx": {
+ default: () => {
+ throw new Error("fail");
+ },
+ },
+ "routes/foo/bar.tsx": {
+ default: () => foo/index
,
+ },
+ });
+
+ let res = await server.get("/fooa");
+ await res.body?.cancel();
+ expect(res.status).toEqual(404);
+
+ res = await server.get("/foo/asdf");
+ await res.body?.cancel();
+ expect(res.status).toEqual(500);
+ },
+);
+
+Deno.test(
+ "fsRoutes - set headers from handler",
+ async () => {
+ const server = await createServer<{ text: string }>({
+ "routes/index.tsx": {
+ handler: (ctx) => {
+ return ctx.render(hello
, {
+ headers: { "X-Foo": "123" },
+ status: 418,
+ statusText: "I'm a fresh teapot",
+ });
+ },
+ },
+ });
+
+ const res = await server.get("/");
+ await res.body?.cancel();
+ expect(res.status).toEqual(418);
+ expect(res.statusText).toEqual("I'm a fresh teapot");
+ expect(res.headers.get("X-Foo")).toEqual("123");
+ },
+);
+
Deno.test("fsRoutes - sortRoutePaths", () => {
let routes = [
"/foo/[id]",
diff --git a/src/plugins/fs_routes/render_middleware.ts b/src/plugins/fs_routes/render_middleware.ts
index 85a39286cab..c41207b93de 100644
--- a/src/plugins/fs_routes/render_middleware.ts
+++ b/src/plugins/fs_routes/render_middleware.ts
@@ -2,6 +2,7 @@ import { type AnyComponent, h, type RenderableProps, type VNode } from "preact";
import type { MiddlewareFn } from "../../middlewares/mod.ts";
import type { HandlerFn, PageResponse } from "../../handlers.ts";
import type { PageProps } from "../../runtime/server/mod.tsx";
+import { HttpError } from "../../error.ts";
export type AsyncAnyComponent = {
(
@@ -20,6 +21,7 @@ export function renderMiddleware(
| AsyncAnyComponent>
>,
handler: HandlerFn | undefined,
+ init?: ResponseInit | undefined,
): MiddlewareFn {
return async (ctx) => {
let result: PageResponse | undefined;
@@ -69,6 +71,23 @@ export function renderMiddleware(
}
}
- return ctx.render(vnode!);
+ let status: number | undefined = init?.status;
+ if (
+ ctx.error !== null && ctx.error !== undefined
+ ) {
+ if (
+ ctx.error instanceof HttpError
+ ) {
+ status = ctx.error.status;
+ } else {
+ status = 500;
+ }
+ }
+
+ return ctx.render(vnode!, {
+ status,
+ statusText: init?.statusText,
+ headers: init?.headers,
+ });
};
}
diff --git a/src/runtime/server/preact_hooks.tsx b/src/runtime/server/preact_hooks.tsx
index 74a9fadc478..6acbe3482c9 100644
--- a/src/runtime/server/preact_hooks.tsx
+++ b/src/runtime/server/preact_hooks.tsx
@@ -26,9 +26,7 @@ import {
import type { BuildCache } from "../../build_cache.ts";
import { BUILD_ID } from "../build_id.ts";
import { DEV_ERROR_OVERLAY_URL } from "../../constants.ts";
-import {
- getCodeFrame,
-} from "../../dev/middlewares/error_overlay/code_frame.tsx";
+import { getCodeFrame } from "../../code_frame.tsx";
import * as colors from "@std/fmt/colors";
import { escape as escapeHtml } from "@std/html";
import { HttpError } from "../../error.ts";