framework: add multiple renderers support

This commit is contained in:
undefined committed 2025-02-21 05:48:13 +08:00
1 parent c48c9f9cf3
commit 4d2b8dfd93
2 files changed
+29 -10

No files matched your search

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