diff --git a/framework/framework/server.ts b/framework/framework/server.ts index 4b278664c..ccacdef14 100644 --- a/framework/framework/server.ts +++ b/framework/framework/server.ts @@ -73,7 +73,6 @@ export interface HydroResponse { attachment: (name: string, stream?: any) => void; addHeader: (name: string, value: string) => void; } -export type RendererFunction = (name: string, context: Record) => string | Promise; type HydroContext = { request: HydroRequest; response: HydroResponse; @@ -90,6 +89,21 @@ export type KoaContext = Koa.Context & { holdFiles: (string | File)[]; }; +export type TextRenderer = { + output: 'html' | 'json' | 'text'; + render: (name: string, args: Record, context: Record) => string | Promise; +}; +export type BinaryRenderer = { + output: 'binary'; + render: (name: string, args: Record, context: Record) => Buffer | Promise; +}; +export type Renderer = (BinaryRenderer | TextRenderer) & { + name: string; + accept: readonly string[]; + priority: number; + asFallback: boolean; +}; + const logger = new Logger('server'); /** @deprecated */ export const koa = new Koa({ @@ -170,14 +184,14 @@ export class HandlerCommon { } renderHTML(templateName: string, args: Record) { - const type = templateName.split('.')[1]; - const engine = this.ctx.server.renderers[type] || (() => JSON.stringify(args, serializer(false, this))); - return engine(templateName, { + const renderers = Object.values(this.ctx.server.renderers).filter((r) => r.accept.includes(templateName) || r.asFallback); + const topPrio = renderers.sort((a, b) => b.priority - a.priority)[0]; + const engine = topPrio?.render || (() => JSON.stringify(args, serializer(false, this))); + return engine(templateName, args, { handler: this, UserContext: this.user, url: this.url, _: this.translate, - ...args, }); } } @@ -338,7 +352,7 @@ export class WebService extends Service { private wsLayers = []; private captureAllRoutes = Object.create(null); - renderers: Record = Object.create(null); + renderers: Record = Object.create(null); server = koa; router = router; HandlerCommon = HandlerCommon; @@ -730,7 +744,7 @@ ${c.response.status} ${endTime - startTime}ms ${c.response.length}`); } } - public registerRenderer(name: string, func: RendererFunction) { + public registerRenderer(name: string, func: Renderer) { if (this.renderers[name]) logger.warn('Renderer %s already exists.', name); this.ctx.effect(() => { this.renderers[name] = func; diff --git a/packages/ui-default/backendlib/template.ts b/packages/ui-default/backendlib/template.ts index 86165628a..18ea48ee7 100644 --- a/packages/ui-default/backendlib/template.ts +++ b/packages/ui-default/backendlib/template.ts @@ -199,7 +199,12 @@ const render = (name: string, state: any) => new Promise((resolve, rejec export const inject = ['server']; export async function apply(ctx: Context) { - ctx.server.registerRenderer('html', render); - ctx.server.registerRenderer('yaml', render); - ctx.server.registerRenderer('md', render); + ctx.server.registerRenderer('ui-default', { + name: 'ui-default', + output: 'html', + accept: [], + asFallback: true, + priority: 1, + render: (name, args, context) => render(name, { ...context, ...args }), + }); }