diff --git a/mocks/app/routes/directory/_error.tsx b/mocks/app/routes/directory/_error.tsx new file mode 100644 index 0000000..11fd6fd --- /dev/null +++ b/mocks/app/routes/directory/_error.tsx @@ -0,0 +1,7 @@ +import type { ErrorHandler } from 'hono' + +const handler: ErrorHandler = (error, c) => { + return c.render(

Custom Error in /directory: {error.message}

) +} + +export default handler diff --git a/mocks/app/routes/directory/sub/throw_error.tsx b/mocks/app/routes/directory/sub/throw_error.tsx new file mode 100644 index 0000000..dc125fb --- /dev/null +++ b/mocks/app/routes/directory/sub/throw_error.tsx @@ -0,0 +1,5 @@ +import { createRoute } from '../../../../../src/factory' + +export default createRoute(() => { + throw new Error('Foo') +}) diff --git a/mocks/app/routes/directory/throw_error.tsx b/mocks/app/routes/directory/throw_error.tsx new file mode 100644 index 0000000..bdf2fb1 --- /dev/null +++ b/mocks/app/routes/directory/throw_error.tsx @@ -0,0 +1,5 @@ +import { createRoute } from '../../../../src/factory' + +export default createRoute(() => { + throw new Error('Foo') +}) diff --git a/src/server/server.ts b/src/server/server.ts index ceefcba..7121836 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -111,6 +111,8 @@ export const createApp = (options: BaseServerOptions): Hono return paths } + const errorHandlerMap: Record = {} + for (const map of routesMap) { for (const [dir, content] of Object.entries(map)) { const subApp = new Hono<{ @@ -186,8 +188,19 @@ export const createApp = (options: BaseServerOptions): Hono } } - // Error - applyError(subApp, dir, errorMap) + // Get an error handler + const errorHandler = getErrorHandler(dir, errorMap) + if (errorHandler) { + errorHandlerMap[dir] = errorHandler + } + + // Apply an error handler + for (const [path, errorHandler] of Object.entries(errorHandlerMap)) { + const regExp = new RegExp(`^${path}`) + if (regExp.test(dir) && errorHandler) { + subApp.onError(errorHandler) + } + } let rootPath = getRootPath(dir) if (trailingSlash) { @@ -241,24 +254,23 @@ function applyNotFound( } } -function applyError( - app: Hono<{ Variables: Variables }>, - dir: string, - map: Record> -) { +function getErrorHandler(dir: string, map: Record>) { for (const [mapDir, content] of Object.entries(map)) { if (dir === mapDir) { const errorFile = content[ERROR_FILENAME] if (errorFile) { - const errorHandler = errorFile.default - app.onError(async (error, c) => { - const importingIslands = errorFile[IMPORTING_ISLANDS_ID] - if (importingIslands) { - c.set(IMPORTING_ISLANDS_ID, importingIslands) + const matchedErrorHandler = errorFile.default + if (matchedErrorHandler) { + const errorHandler: ErrorHandler = async (error, c) => { + const importingIslands = errorFile[IMPORTING_ISLANDS_ID] + if (importingIslands) { + c.set(IMPORTING_ISLANDS_ID, importingIslands) + } + c.status(500) + return matchedErrorHandler(error, c) } - c.status(500) - return errorHandler(error, c) - }) + return errorHandler + } } } } diff --git a/test-integration/apps.test.ts b/test-integration/apps.test.ts index 938e193..01d7f13 100644 --- a/test-integration/apps.test.ts +++ b/test-integration/apps.test.ts @@ -158,6 +158,26 @@ describe('Basic', () => { method: 'GET', handler: expect.any(Function), }, + { + path: '/directory/throw_error', + method: 'GET', + handler: expect.any(Function), + }, + { + path: '/directory/throw_error', + method: 'GET', + handler: expect.any(Function), + }, + { + path: '/directory/sub/throw_error', + method: 'GET', + handler: expect.any(Function), + }, + { + path: '/directory/sub/throw_error', + method: 'GET', + handler: expect.any(Function), + }, { path: '/fc', method: 'GET', @@ -264,7 +284,7 @@ describe('With preserved', () => { eager: true, }) - const ERROR = import.meta.glob('../mocks/app/routes/_error.tsx', { + const ERROR = import.meta.glob('../mocks/app/routes/**/_error.tsx', { eager: true, }) @@ -378,6 +398,22 @@ describe('With preserved', () => { 'Internal Server Error

Custom Error Message: Foo

' ) }) + + it('Should return 500 response - /directory/throw_error', async () => { + const res = await app.request('/directory/throw_error') + expect(res.status).toBe(500) + expect(await res.text()).toBe( + '

Custom Error in /directory: Foo

' + ) + }) + + it('Should return 500 response - /directory/sub/throw_error', async () => { + const res = await app.request('/directory/sub/throw_error') + expect(res.status).toBe(500) + expect(await res.text()).toBe( + '

Custom Error in /directory: Foo

' + ) + }) }) describe('API', () => {