Server/Packages/Server Renderer/API reference
@sigx/server-renderer · Stable

API reference#

Every public export of @sigx/server-renderer v0.5.0, grouped by kind. The import path for each symbol is noted, since the package splits into three subpaths: @sigx/server-renderer (main), @sigx/server-renderer/server, and @sigx/server-renderer/client.

Render functions#

renderToString#

Render a JSX element or App to a complete HTML string. Awaits all async (ssr.load) components and plugin streaming chunks before resolving. Accepts an App from defineApp() (extracts the root component + AppContext for DI) or a raw JSX element.

TypeScript
function renderToString(input: JSXElement | App, context?: SSRContext): Promise<string>
  • input — a raw JSX element, or an App from defineApp().
  • context — optional pre-built SSRContext (auto-created if omitted).
  • Returns — a promise resolving to the full HTML string.
  • Exported from the main entry and /server.

renderToStream#

Render to a web ReadableStream<string>. Pull-based with 4KB chunk batching and natural backpressure; streams the shell first, then async-component replacement scripts interleaved as they resolve, then a final completion script. Recommended default.

TypeScript
function renderToStream(input: JSXElement | App, context?: SSRContext): ReadableStream<string>
  • input — JSX element or App.
  • context — optional SSRContext.
  • Returns — a web ReadableStream<string>.
  • Exported from the main entry and /server.

renderToNodeStream#

Render to a Node.js Readable stream (objectMode), bypassing WebStream overhead. Faster than renderToStream() on Node — recommended for Express/Fastify/H3. Pipe directly to the HTTP response.

TypeScript
function renderToNodeStream(input: JSXElement | App, context?: SSRContext): Readable
  • input — JSX element or App.
  • context — optional SSRContext.
  • Returns — a Node Readable (pipe to the response: stream.pipe(res)).
  • Exported from /server only (not the main entry).

renderToStreamWithCallbacks#

Callback-based streaming for fine-grained control. Calls onShellReady(html) once with the full synchronous shell (including plugin-injected HTML and the completion script), then onAsyncChunk(chunk) per resolved async component, then onComplete(); onError(err) on failure.

TypeScript
function renderToStreamWithCallbacks(input: JSXElement | App, callbacks: StreamCallbacks, context?: SSRContext): Promise<void>
  • input — JSX element or App.
  • callbacks — a StreamCallbacks set.
  • context — optional SSRContext.
  • Returns — a promise that resolves when streaming completes.
  • Exported from /server only (not the main entry).

renderVNodeToString#

Low-level helper that renders a single VNode subtree to an HTML string using an existing SSRContext (used internally for deferred async content).

TypeScript
function renderVNodeToString(element: JSXElement, ctx: SSRContext, appContext?: AppContext | null): Promise<string>
  • element — the VNode subtree to render.
  • ctx — an existing SSRContext.
  • appContext — optional AppContext for DI.
  • Returns — a promise resolving to the subtree's HTML.
  • Exported from the main entry and /server.

SSR instance & context#

createSSR#

Creates a plugin-driven SSR instance. Register plugins via .use(), then render with .render()/.renderStream()/.renderNodeStream()/.renderStreamWithCallbacks(). With no plugins, the hooks are no-ops and it behaves like the standalone renderToString/renderToStream functions. The strategy-agnostic core — islands/selective/resumable hydration are layered on as SSRPlugins.

TypeScript
function createSSR(): SSRInstance
  • Returns — an SSRInstance.
  • Exported from the main entry.

createSSRContext#

Create a fresh SSRContext that tracks component IDs/markers, collected <head> HTML, plugin data, streaming mode, and pending async components.

TypeScript
function createSSRContext(options?: SSRContextOptions): SSRContext
  • optionsstreaming and onComponentError.
  • Returns — a new SSRContext.
  • Exported from the main entry and /server.

Head management#

useHead#

Composable to manage <head> elements (title, titleTemplate, meta, link, script, htmlAttrs, bodyAttrs) from inside a component. During SSR it collects configs into the active SSRContext; on the client it mutates the DOM directly and registers cleanup on component unmount.

TypeScript
function useHead(config: HeadConfig): void
  • config — a HeadConfig.
  • Exported from the main entry.

renderHeadToString#

Render an array of collected HeadConfig objects to an HTML string. Dedupes meta by name/property/http-equiv/charset, applies the last title (through titleTemplate's %s if set), and HTML/attr-escapes output.

TypeScript
function renderHeadToString(configs: HeadConfig[]): string
  • configs — collected HeadConfig objects.
  • Returns — the head HTML string.
  • Exported from the main entry.

enableSSRHead#

Switch head management into SSR-collection mode and reset the buffer. Called by the renderer before rendering so useHead() collects instead of touching the DOM.

TypeScript
function enableSSRHead(): void
  • Exported from the main entry.

collectSSRHead#

Disable SSR head mode and return (and clear) the HeadConfigs collected since enableSSRHead(). Pass the result to renderHeadToString().

TypeScript
function collectSSRHead(): HeadConfig[]
  • Returns — the collected HeadConfig[].
  • Exported from the main entry.

Streaming script helpers#

generateStreamingScript#

Returns the one-time client bootstrap <script> defining window.$SIGX_REPLACE(id, html), which swaps an async placeholder ([data-async-placeholder="id"]) with rendered HTML and dispatches a sigx:async-ready CustomEvent. Emitted once before any replacement scripts.

TypeScript
function generateStreamingScript(): string
  • Returns — the bootstrap script HTML.
  • Exported from /server.

generateReplacementScript#

Generate the <script>$SIGX_REPLACE(id, "...escaped html...")</script> for a resolved async component, used during streaming to replace its placeholder.

TypeScript
function generateReplacementScript(id: number, html: string, extraScript?: string): string
  • id — the async component id.
  • html — rendered HTML to inject.
  • extraScript — optional extra script appended after the replacement call.
  • Returns — the replacement script HTML.
  • Exported from /server.

escapeJsonForScript#

Escape a JSON string for safe embedding inside a <script> tag (replaces <, >, U+2028, U+2029) to prevent XSS / script-context breakout.

TypeScript
function escapeJsonForScript(json: string): string
  • json — the JSON string to escape.
  • Returns — the escaped string.
  • Exported from /server.

generateSignalKey#

Generate the stable serialization key for a signal during SSR state capture/restore. Named signals use the name; unnamed use a positional key ($0, $1, …). Server (tracking) and client (restoring) MUST both use this for key parity.

TypeScript
function generateSignalKey(name: string | undefined, index: number): string
  • name — the signal's name, or undefined for positional keying.
  • index — the declaration index for unnamed signals.
  • Returns — the serialization key.
  • Exported from the main entry and /server.

Client hydration#

ssrClientPlugin#

A sigx app Plugin that adds app.hydrate(container) to the App instance. hydrate() resolves a string selector or Element, finds the root component + AppContext, and hydrates existing SSR DOM (or falls back to client-side render() when the container has no SSR content).

TypeScript
const ssrClientPlugin: Plugin
  • Use via defineApp(<App/>).use(ssrClientPlugin).hydrate('#root').
  • Exported from the main entry and /client.

hydrate#

Core hydration entry: normalizes element to a VNode, sets the current AppContext for DI, runs registered client plugins' beforeHydrate (return false to skip the DOM walk, e.g. resumable SSR), walks existing SSR DOM via hydrateNode, then runs afterHydrate hooks. Stores _vnode on the container.

TypeScript
function hydrate(element: any, container: Element, appContext?: AppContext): void
  • Exported from /client.

hydrateNode#

Hydrate a single VNode against existing DOM (no DOM creation in the happy path); attaches events/props/directives/refs, skips SSR comment markers (<!--t-->, <!--$c:N-->), recovers from minor SSR drift by scanning forward (dev warns), and returns the next sibling DOM node. Recurses for fragments/components/elements.

TypeScript
function hydrateNode(vnode: VNode, dom: Node | null, parent: Node): Node | null
  • Exported from /client.

hydrateComponent#

Hydrate a single component: locates its trailing <!--$c:N--> marker, builds reactive props/slots, creates the ComponentSetupContext (with a client ssr helper whose load() is a no-op when serverState is present), runs setup, and creates the reactive effect that hydrates-on-first-run then patches. Used by SSR strategy plugins for selective/island hydration.

TypeScript
function hydrateComponent(vnode: VNode, dom: Node | null, parent: Node, serverState?: Record<string, any>, trailingMarker?: Comment | null): Node | null
  • Exported from /client.

registerClientPlugin#

Register a client-side SSRPlugin so its client.beforeHydrate/hydrateComponent/afterHydrate hooks run during hydration. The mechanism behind selective/island/resumable hydration strategies.

TypeScript
function registerClientPlugin(plugin: SSRPlugin): void
  • Exported from /client.

getClientPlugins / clearClientPlugins#

Return all currently registered client-side SSRPlugins, or clear them (useful in tests).

TypeScript
function getClientPlugins(): SSRPlugin[]
function clearClientPlugins(): void
  • Exported from /client.

createRestoringSignal#

Create a signal() replacement that restores values from server-captured state by key (via generateSignalKey), avoiding client re-fetch during hydration. Dev-warns once if an unnamed (positional-key) signal is restored, since declaration-order drift between server/client builds silently mismatches state.

TypeScript
function createRestoringSignal(serverState: Record<string, any>): SSRSignalFn
  • Exported from /client.

setPendingServerState#

Set server-captured signal state to apply to the next component mounted during hydration (used internally when mounting async components after streaming). The context extension consumes and clears it.

TypeScript
function setPendingServerState(state: Record<string, any> | null): void
  • Exported from /client.

getCurrentAppContext / setCurrentAppContext#

Get or set the AppContext tracked during hydration (for DI in deferred/island hydration callbacks).

TypeScript
function getCurrentAppContext(): AppContext | null
function setCurrentAppContext(ctx: AppContext | null): void
  • Exported from /client.

Interfaces & types#

SSRInstance#

The object returned by createSSR(). use() is chainable. Render methods accept SSRContextOptions or a pre-built SSRContext. createContext() builds a raw SSRContext with this instance's plugins pre-configured.

TypeScript
interface SSRInstance {
  use(plugin: SSRPlugin): SSRInstance;
  render(input: JSXElement | App, options?: SSRContextOptions | SSRContext): Promise<string>;
  renderStream(input: JSXElement | App, options?: SSRContextOptions | SSRContext): ReadableStream<string>;
  renderNodeStream(input: JSXElement | App, options?: SSRContextOptions | SSRContext): import('node:stream').Readable;
  renderStreamWithCallbacks(input: JSXElement | App, callbacks: StreamCallbacks, options?: SSRContextOptions | SSRContext): Promise<void>;
  createContext(options?: SSRContextOptions): SSRContext;
}
  • Exported as a type from the main entry.

SSRPlugin#

The strategy-agnostic extension interface that implements selective/island/resumable/Suspense hydration without core changes. Server hooks fire during render; client hooks fire during hydration.

TypeScript
interface SSRPlugin {
  name: string;
  server?: {
    setup?(ctx: SSRContext): void;
    transformComponentContext?(ctx: SSRContext, vnode: VNode, componentCtx: ComponentSetupContext): ComponentSetupContext | void;
    afterRenderComponent?(id: number, vnode: VNode, html: string, ctx: SSRContext): string | void;
    handleAsyncSetup?(id: number, ssrLoads: Promise<void>[], renderFn: () => any, ctx: SSRContext): { mode: 'block' | 'stream' | 'skip'; placeholder?: string } | void;
    onAsyncComponentResolved?(id: number, html: string, ctx: SSRContext): { html?: string; script?: string } | void;
    getInjectedHTML?(ctx: SSRContext): string | Promise<string>;
    getStreamingChunks?(ctx: SSRContext): AsyncGenerator<string> | void;
  };
  client?: {
    beforeHydrate?(container: Element): boolean | void;
    hydrateComponent?(vnode: VNode, dom: Node | null, parent: Node): Node | null | undefined;
    afterHydrate?(container: Element): void;
  };
}
  • client.beforeHydrate returning false skips the default DOM walk (resumable).
  • client.hydrateComponent returning a Node claims a component (islands intercept client:* props).
  • Exported as a type from the main entry.

SSRContext#

Per-render context tracking component IDs/markers, collected head HTML, streaming flag, pending async components, and per-plugin data (get/setPluginData keyed by plugin name).

TypeScript
interface SSRContext {
  _componentId: number;
  _componentStack: number[];
  _head: string[];
  _onComponentError?: (error: Error, componentName: string, componentId: number) => string | null;
  _plugins?: SSRPlugin[];
  _pluginData: Map<string, any>;
  _streaming: boolean;
  _pendingAsync: CorePendingAsync[];
  nextId(): number;
  pushComponent(id: number): void;
  popComponent(): number | undefined;
  addHead(html: string): void;
  getHead(): string;
  getPluginData<T>(pluginName: string): T | undefined;
  setPluginData<T>(pluginName: string, data: T): void;
}
  • Exported as a type from the main entry and /server.

SSRContextOptions#

Options for createSSRContext() and the render methods. streaming defaults to true. onComponentError returns fallback HTML for a component whose setup() throws, or null for the default error placeholder.

TypeScript
interface SSRContextOptions {
  streaming?: boolean;
  onComponentError?: (error: Error, componentName: string, componentId: number) => string | null;
}
  • Exported as a type from the main entry and /server.

RenderOptions#

Optional wrapper carrying a custom SSRContext (auto-created if absent).

TypeScript
interface RenderOptions {
  context?: SSRContext;
}
  • Exported as a type from the main entry and /server.

CorePendingAsync#

A core-managed pending async component: its component id plus a promise resolving to its rendered HTML once ssr.load() completes. Populated by render-core in streaming mode when no plugin overrides.

TypeScript
interface CorePendingAsync {
  id: number;
  promise: Promise<string>;
}
  • Exported as a type from the main entry and /server.

StreamCallbacks#

Callback set for renderToStreamWithCallbacks(): onShellReady(shell html), onAsyncChunk(per resolved async component), onComplete(), onError(err).

TypeScript
interface StreamCallbacks {
  onShellReady: (html: string) => void;
  onAsyncChunk: (chunk: string) => void;
  onComplete: () => void;
  onError: (error: Error) => void;
}
  • Exported as a type from /server.

SSRHelper#

The ssr object injected into every ComponentSetupContext. ssr.load(fn) runs async data fetching on the server and is skipped on the client during hydration (state restored from server). isServer/isHydrating flags.

TypeScript
interface SSRHelper {
  load(fn: () => Promise<void>): void;
  readonly isServer: boolean;
  readonly isHydrating: boolean;
}
  • Exported as a type from the main entry.

HeadConfig & friends#

Config objects passed to useHead()/renderHeadToString(). titleTemplate uses %s as the title placeholder; meta is deduped by name/property/http-equiv/charset.

TypeScript
interface HeadConfig {
  title?: string;
  titleTemplate?: string;
  meta?: HeadMeta[];
  link?: HeadLink[];
  script?: HeadScript[];
  htmlAttrs?: { lang?: string; dir?: string; [key: string]: string | undefined };
  bodyAttrs?: { class?: string; [key: string]: string | undefined };
}

HeadMeta, HeadLink and HeadScript are the per-tag descriptors (boolean script attrs like async/defer render as bare attributes; innerHTML becomes the script body). All exported as types from the main entry.

SSRSignalFn#

signal() function type augmented with an optional name used as the hydration serialization key. Shared by server tracking signals and client restoring signals.

TypeScript
type SSRSignalFn = {
  <T extends Primitive>(initial: T, name?: string): PrimitiveSignal<T>;
  <T extends object>(initial: T, name?: string): Signal<T>;
}
  • Exported as a type from the main entry and /server (re-exported from /client).

HydrateFn#

The hydrate function signature (mirrors the MountFn pattern).

TypeScript
type HydrateFn<TContainer = any> = (element: any, container: TContainer, appContext: AppContext) => (() => void) | void
  • Exported from /client alongside ssrClientPlugin.

ComponentFactory / InternalVNode#

ComponentFactory is the minimal component-factory shape consumed by hydrateComponent; InternalVNode is a VNode extended with internal hydration bookkeeping (subtree refs, reactive effect, props/slots), exposed for plugin authors. Both exported as types from /client.

Module augmentations#

The package augments @sigx/runtime-core via declare module to integrate SSR into the core framework types. These apply automatically on import: getSSRProps on directive definitions, hydrate() on App (via ssrClientPlugin), and the ssr helper on ComponentSetupContext.

The client:* directive types (client:load, client:visible, …) are not part of this package — they ship with @sigx/ssr-islands via its /jsx subpath.