Skip to content

Commit

Permalink
feat: allow stacking error handlers (#3085)
Browse files Browse the repository at this point in the history
  • Loading branch information
pi0 authored Feb 12, 2025
1 parent 2ebb0e3 commit 722d586
Show file tree
Hide file tree
Showing 7 changed files with 61 additions and 6 deletions.
12 changes: 8 additions & 4 deletions src/core/config/resolvers/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@ import { join } from "pathe";

export async function resolveErrorOptions(options: NitroOptions) {
if (!options.errorHandler) {
options.errorHandler = join(
runtimeDir,
`internal/error/${options.dev ? "dev" : "prod"}`
);
options.errorHandler = [];
} else if (!Array.isArray(options.errorHandler)) {
options.errorHandler = [options.errorHandler];
}

// Always add the default error handler as the last one
options.errorHandler.push(
join(runtimeDir, `internal/error/${options.dev ? "dev" : "prod"}`)
);
}
5 changes: 4 additions & 1 deletion src/rollup/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { sourcemapMininify } from "./plugins/sourcemap-min";
import { storage } from "./plugins/storage";
import { timing } from "./plugins/timing";
import { virtual } from "./plugins/virtual";
import { errorHandler } from "./plugins/error-handler";
import { resolveAliases } from "./utils";

export const getRollupConfig = (nitro: Nitro): RollupConfig => {
Expand Down Expand Up @@ -344,6 +345,9 @@ export const getRollupConfig = (nitro: Nitro): RollupConfig => {
rollupConfig.plugins.push(handlersMeta(nitro));
}

// Error handler
rollupConfig.plugins.push(errorHandler(nitro));

// Polyfill
rollupConfig.plugins.push(
virtual(
Expand Down Expand Up @@ -393,7 +397,6 @@ export const plugins = [
alias({
entries: resolveAliases({
"#build": buildDir,
"#nitro-internal-virtual/error-handler": nitro.options.errorHandler,
"#internal/nitro": runtimeDir,
"nitro/runtime": runtimeDir,
"nitropack/runtime": runtimeDir,
Expand Down
36 changes: 36 additions & 0 deletions src/rollup/plugins/error-handler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Nitro } from "nitropack/types";
import { virtual } from "./virtual";

export function errorHandler(nitro: Nitro) {
return virtual(
{
"#nitro-internal-virtual/error-handler": () => {
const errorHandlers = Array.isArray(nitro.options.errorHandler)
? nitro.options.errorHandler
: [nitro.options.errorHandler];

return /* js */ `
${errorHandlers.map((h, i) => `import errorHandler$${i} from "${h}";`).join("\n")}
const errorHandlers = [${errorHandlers.map((_, i) => `errorHandler$${i}`).join(", ")}];
export default async function(error, event) {
for (const handler of errorHandlers) {
try {
await handler(error, event);
if (event.handled) {
return; // Response handled
}
} catch(error) {
// Handler itself thrown, log and continue
console.error(error);
}
}
// H3 will handle fallback
}
`;
},
},
nitro.vfs
);
}
2 changes: 1 addition & 1 deletion src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ export interface NitroOptions extends PresetOptions {
handlers: NitroEventHandler[];
routeRules: { [path: string]: NitroRouteRules };
devHandlers: NitroDevEventHandler[];
errorHandler: string;
errorHandler: string | string[];
devErrorHandler: NitroErrorHandler;
prerender: {
/**
Expand Down
5 changes: 5 additions & 0 deletions test/fixture/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default defineNitroErrorHandler((error, event) => {
if (event.path.includes("?custom_error_handler")) {
return send(event, "custom_error_handler");
}
});
1 change: 1 addition & 0 deletions test/fixture/nitro.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export default defineNitroConfig({
"db:migrate": { description: "Migrate database" },
"db:seed": { description: "Seed database" },
},
errorHandler: "~/error.ts",
routeRules: {
"/api/param/prerender4": { prerender: true },
"/api/param/prerender2": { prerender: false },
Expand Down
6 changes: 6 additions & 0 deletions test/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,12 @@ export function testNitro(
"x-content-type-options": "nosniff",
"x-frame-options": "DENY",
});

const { data } = await callHandler({
url: "/api/error?custom_error_handler",
});
expect(status).toBe(503);
expect(data).toBe("custom_error_handler");
});

it.skipIf(isWindows && ctx.preset === "nitro-dev")(
Expand Down

0 comments on commit 722d586

Please sign in to comment.