Progressive SSR and Trusted Types
Stream apps with Declarative Shadow DOM and configure CSP and HTML policies.
This page describes WU Framework 4.0.0. Read the Framework 4.0 and CLI 1.2 migration guide before upgrading an existing project.
Streaming per application
import { renderAppsStream, streamToString, createNonce,
securityHeaders } from 'wu-framework/server';
const nonce = createNonce();
const headers = securityHeaders({ nonce, https: false });
const stream = renderAppsStream([
{ name: 'summary', module: { render: async () => ({
html: '<p>Summary ready</p>', styles: 'p { color: teal }',
state: { ready: true },
}) } },
{ name: 'details', module: { render: async () => '<p>Details ready</p>' } },
], {
order: 'ready', nonce,
head: '<!doctype html><html lang="en"><head><title>WU stream</title></head><body>',
tail: '</body></html>',
onError: ({ app, error }) => console.error(app, error),
});
// Fetch-compatible server handler: return this Response.
const response = new Response(stream, { headers: {
...headers, 'Content-Type': 'text/html; charset=utf-8',
} });
// Tests may consume a fresh stream with await streamToString(stream).
Renders start up to the concurrency limit; without a limit, they start together. order: "document" delivers apps in order and needs no scripts to reposition them. order: "ready" delivers each app when complete, leaves placeholders and requires a nonce for scripts that move already parsed nodes. The streaming unit is the whole app, not each renderer component. streamToString consumes the stream: do not try to read it again afterwards.
state: false omits the final state script; stateVarName changes its name. With failFast: true, an error aborts the stream; by default the slot remains and onError runs. Connect the client module and hydration lifecycle for interactivity: server HTML does not mount client renderers by itself. renderReact supports auto, static and string according to the installed React DOM APIs.
HTML policies and CSP
On the server, securityHeaders({ nonce, trustedTypes: true }) generates the corresponding directives. A trustedTypes array replaces the allowed policy list. Use a fresh nonce per response and the same value in that response header, styles and scripts. Configure HTTPS and the origins your shell actually needs in production.
import { wu } from 'wu-framework';
await wu.init({ trustedTypes: 'sanitize', apps: [] });
true and "sanitize" install a default HTML policy using the WU sanitizer. "report" records writes without sanitizing them; use it for diagnosis, not protection. "strict" rejects unsealed strings. WU respects an existing default policy. Policies are neither JavaScript isolation nor authorization for remote resources, and they do not replace grants or application data validation.
Configure signal, timeout and concurrency to bound stream work. The SSR reference explains cancellation, private loaders and the createServerRequest lifecycle.