renderToFlowEvents
The primitive under renderToStream: a ReadableStream<FlowEvent> of raw
events instead of adapter-encoded HTML, for a wire format the built-in adapters
don't cover.
Signature#
import { renderToFlowEvents } from "@vincle/flow";
function renderToFlowEvents( node: () => JSX.Element, adapter: StreamingAdapter, opts?: FlowOptions & { mode?: "full" | "fragment" },): ReadableStream<FlowEvent>;Same arguments as renderToStream; a non-streaming
adapter (EsiAdapter) is rejected at compile time and at runtime.
Events#
FlowEvent is a discriminated union:
| Event | Shape | Emitted when |
|---|---|---|
shell |
{ type: "shell"; html: string } |
The page shell is fully rendered (one event) |
fragment |
{ type: "fragment"; id: string; html: string; merge: MergeType } |
A deferred fragment is ready; html is the raw inner content, merge is that template's merge type |
close |
{ type: "close"; html: string } |
The closing </body></html> tags, after all fragments |
The shell is one event, emitted once fully rendered; fragments follow as they
resolve, one event each (one per yielded item for an AsyncIterable).
mode: "fragment" suppresses the shell and close events.
Consuming the events#
import { renderToFlowEvents } from "@vincle/flow";import { NativeAdapter } from "@vincle/flow/adapters";
const stream = renderToFlowEvents(() => <Page />, NativeAdapter);
for await (const ev of stream) { switch (ev.type) { case "shell": // ev.html: the full shell, before closing tags break; case "fragment": // ev.id, ev.html, ev.merge: patch into the shell yourself break; case "close": // ev.html: trailing </body></html> break; }}The stream handles backpressure; cancelling it (or aborting opts.signal)
aborts pending renders.