85 lines
2.5 KiB
TypeScript
85 lines
2.5 KiB
TypeScript
import type { ComponentMetadata } from "../decorators/Component.ts";
|
|
|
|
/**
|
|
* Server components.
|
|
*
|
|
* A server component is a class that renders html on the server. It behaves
|
|
* like a template, but it is written in TypeScript, may inject services and
|
|
* may be asynchronous.
|
|
*/
|
|
|
|
/** Context handed to a server component. */
|
|
export interface ComponentContext {
|
|
/**
|
|
* Defers a chunk of html until the end of the response.
|
|
*
|
|
* The response is streamed, therefore the shell reaches the browser
|
|
* before the deferred content is rendered.
|
|
*/
|
|
defer(id: string, content: string | Promise<string>): void;
|
|
/** Locals of the current request. */
|
|
locals: Record<string, unknown>;
|
|
/** Route parameters of the current request. */
|
|
params: Record<string, string>;
|
|
}
|
|
|
|
/** Declarative output from a decorated server component. */
|
|
export interface SpugComponentRender {
|
|
/** Component template name or path, resolved as SPUG. */
|
|
spug: string;
|
|
/** STCSS source or a stylesheet path relative to the component directory. */
|
|
stcss?: string | string[];
|
|
/** Props merged with the invocation props before rendering the SPUG template. */
|
|
props?: Record<string, unknown>;
|
|
}
|
|
|
|
/** Contract of a server component. */
|
|
export interface ServerComponent {
|
|
/** Renders the component. */
|
|
render(
|
|
props: Record<string, unknown>,
|
|
context: ComponentContext,
|
|
): Promise<string | SpugComponentRender> | string | SpugComponentRender;
|
|
}
|
|
|
|
export function isSpugComponentRender(
|
|
value: unknown,
|
|
): value is SpugComponentRender {
|
|
return (
|
|
typeof value === "object" &&
|
|
value !== null &&
|
|
typeof (value as { spug?: unknown }).spug === "string"
|
|
);
|
|
}
|
|
|
|
/** A registered server component. */
|
|
export interface ComponentDefinition {
|
|
/** Name used inside the templates. */
|
|
name: string;
|
|
component: ServerComponent;
|
|
/** `true` when the component is rendered after the shell. */
|
|
deferred: boolean;
|
|
description?: string;
|
|
params?: Record<string, string>;
|
|
/** Decorated components must return a SPUG and STCSS composition. */
|
|
requiresSpug?: boolean;
|
|
}
|
|
|
|
/** Registry of the server components of an application. */
|
|
export type ComponentRegistry = Map<string, ComponentDefinition>;
|
|
|
|
/** Builds a component definition from a decorated class. */
|
|
export function defineComponent(
|
|
name: string,
|
|
component: ServerComponent,
|
|
metadata?: ComponentMetadata,
|
|
): ComponentDefinition {
|
|
return {
|
|
name,
|
|
component,
|
|
deferred: metadata?.deferred === true,
|
|
description: metadata?.description,
|
|
params: metadata?.params,
|
|
requiresSpug: metadata !== undefined,
|
|
};
|
|
}
|