renderToStream
Renders an app as a stream of HTML, for the fastest first byte: the shell first (pending Suspense boundaries show their fallback), then one chunk per boundary as its data arrives, in the order the data settles, and finally, when resources resolved, a <script type="application/json" data-sh="RENDER_ID"> block with their values.
Renders an app as a stream of HTML, for the fastest first byte: the shell first (pending Suspense
boundaries show their fallback), then one chunk per boundary as its data arrives, in the order the
data settles, and finally, when resources resolved, a
<script type="application/json" data-sh="RENDER_ID"> block with their values. The page works without JavaScript: each chunk is a <template> that a
tiny inline script swaps in for the fallback. A boundary whose data can no longer arrive keeps its
fallback for the client.
Import#
import { renderToStream } from "@shadow-js/web/server";
Signature#
function renderToStream(
code: () => unknown,
options: StreamOptions = {},
): ReadableStream<Uint8Array>
Parameters#
| Name | Description |
|---|---|
code |
Builds the app. |
options |
Hydration-key prefix, nonce, time budget, abort signal, collectors, shell callback and error reporters. Undefined uses the defaults of StreamOptions. |
Returns#
A byte stream of the app markup, to be placed inside your document. Canceling it stops the render.
Throws#
- TypeError, synchronously, for an invalid
renderIdortimeoutMs. The stream itself errors with anSsrErrorwhosecodeisSSR_TIMEOUTwhentimeoutMsruns out, with the signal's reason whensignalaborts, and with an error no boundary caught whenonUncaughtErroris not set.
Examples#
import { createComponent, renderToStream } from "@shadow-js/web/server";
function App() {
return <h1>Hello</h1>;
}
function handle(request: Request): Response {
const stream = renderToStream(() => createComponent(App, {}), { signal: request.signal });
return new Response(stream, { headers: { "content-type": "text/html" } });
}