From f99e0e74e98954aa9a222e1c47c913e94a87993d Mon Sep 17 00:00:00 2001 From: killagu Date: Tue, 14 Apr 2026 10:54:49 +0800 Subject: [PATCH] refactor(onerror): inline error page template as string constant Inline the mustache error page template as a string constant in src/lib/onerror_page.ts so plugins can be statically bundled by turbopack. Previously the template was read from disk via `import.meta.dirname + readFileSync`, which breaks when modules are embedded in a single bundled chunk. `templatePath` default is now `''`; if set, the custom template file is still loaded via fs, otherwise the inlined constant is used. Co-Authored-By: Claude Opus 4.6 (1M context) --- plugins/onerror/package.json | 2 + plugins/onerror/src/app.ts | 3 +- plugins/onerror/src/config/config.default.ts | 8 +- plugins/onerror/src/lib/onerror_page.ts | 1336 ++++++++++++++++++ 4 files changed, 1344 insertions(+), 5 deletions(-) create mode 100644 plugins/onerror/src/lib/onerror_page.ts diff --git a/plugins/onerror/package.json b/plugins/onerror/package.json index 926a44d61e..e21b75a202 100644 --- a/plugins/onerror/package.json +++ b/plugins/onerror/package.json @@ -28,6 +28,7 @@ "./app": "./src/app.ts", "./config/config.default": "./src/config/config.default.ts", "./lib/error_view": "./src/lib/error_view.ts", + "./lib/onerror_page": "./src/lib/onerror_page.ts", "./lib/utils": "./src/lib/utils.ts", "./types": "./src/types.ts", "./package.json": "./package.json" @@ -40,6 +41,7 @@ "./app": "./dist/app.js", "./config/config.default": "./dist/config/config.default.js", "./lib/error_view": "./dist/lib/error_view.js", + "./lib/onerror_page": "./dist/lib/onerror_page.js", "./lib/utils": "./dist/lib/utils.js", "./types": "./dist/types.js", "./package.json": "./package.json" diff --git a/plugins/onerror/src/app.ts b/plugins/onerror/src/app.ts index fe3444c733..a525754d61 100644 --- a/plugins/onerror/src/app.ts +++ b/plugins/onerror/src/app.ts @@ -6,6 +6,7 @@ import { onerror, type OnerrorOptions, type OnerrorError } from 'koa-onerror'; import type { OnerrorConfig } from './config/config.default.ts'; import { ErrorView } from './lib/error_view.ts'; +import { ONERROR_PAGE_TEMPLATE } from './lib/onerror_page.ts'; import { isProd, detectStatus, detectErrorMessage, accepts } from './lib/utils.ts'; export interface OnerrorErrorWithCode extends OnerrorError { @@ -23,7 +24,7 @@ export default class Boot implements ILifecycleBoot { async didLoad(): Promise { // logging error const config = this.app.config.onerror; - const viewTemplate = fs.readFileSync(config.templatePath, 'utf8'); + const viewTemplate = config.templatePath ? fs.readFileSync(config.templatePath, 'utf8') : ONERROR_PAGE_TEMPLATE; const app = this.app; app.on('error', (err, ctx) => { if (!ctx) { diff --git a/plugins/onerror/src/config/config.default.ts b/plugins/onerror/src/config/config.default.ts index 9aa66b0016..dc7a5e5ee5 100644 --- a/plugins/onerror/src/config/config.default.ts +++ b/plugins/onerror/src/config/config.default.ts @@ -1,5 +1,3 @@ -import path from 'node:path'; - import type { Context } from 'egg'; import type { OnerrorError, OnerrorOptions } from 'koa-onerror'; @@ -20,7 +18,9 @@ export interface OnerrorConfig extends OnerrorOptions { */ appErrorFilter?: (err: OnerrorError, ctx: Context) => boolean; /** - * default template path + * Custom template path. If empty, uses the built-in error page template. + * + * Default: `''` */ templatePath: string; } @@ -29,6 +29,6 @@ export default { onerror: { errorPageUrl: '', appErrorFilter: undefined, - templatePath: path.join(import.meta.dirname, '../lib/onerror_page.mustache.html'), + templatePath: '', } as OnerrorConfig, }; diff --git a/plugins/onerror/src/lib/onerror_page.ts b/plugins/onerror/src/lib/onerror_page.ts new file mode 100644 index 0000000000..b045973009 --- /dev/null +++ b/plugins/onerror/src/lib/onerror_page.ts @@ -0,0 +1,1336 @@ +/** Error page template - inlined from onerror_page.mustache.html */ +export const ONERROR_PAGE_TEMPLATE = ` + + + + + + + + + + + +
+
+

{{ status }}

+
+

{{ name }} in {{ request.url }}

+
{{ message }}
+
+ + + +
+ + +
+
+ + +
+ +
+ {{#frames}} {{index}} +
+
{{ file }}:{{ line }}:{{ column }}
+
{{ method }}
+
+ {{ context.pre }} {{ context.line }} {{ context.post }} +
+
+ {{/frames}} +
+
+
+
+ +
+

Request Details

+
+
+
URI
+
{{ request.url }}
+
+ +
+
Request Method
+
{{ request.method }}
+
+ +
+
HTTP Version
+
{{ request.httpVersion }}
+
+ +
+
Connection
+
{{ request.connection }}
+
+
+ +

Headers

+
+ {{#request.headers}} +
+
{{ key }}
+
{{ value }}
+
+ {{/request.headers}} +
+ +

Cookies

+
+ {{#request.cookies}} +
+
{{ key }}
+
{{ value }}
+
+ {{/request.cookies}} +
+

AppInfo

+
+
+
baseDir
+
{{ appInfo.baseDir }}
+
+
+
config
+
+
{{ appInfo.config }}
+
+
+
+
+ + + +
+ + +`;