Referência de renderização e segurança HTTP
Contratos completos de SSR, adaptadores do servidor, serialização e cabeçalhos.
Servidor e navegador têm responsabilidades diferentes
Importe estas funções de wu-framework/server, wu-framework/server/adapters ou wu-framework/server/security. A renderização recebe módulos de servidor explícitos; não monta componentes do navegador nem baixa automaticamente a entrada de um manifesto.
Cada solicitação deve manter seu próprio estado e nonce. O HTML do renderizador é conteúdo confiável: use escapeHtml para dados externos e evite enviar segredos em renderStateScript. A receita de servidor mostra como compor a resposta e sua hidratação.
Os nomes RenderResult e RenderOutput desta página descrevem o formato dos resultados; consulte as declarações do subcaminho server para importar tipos efetivamente exportados.
renderApp
Renderiza uma aplicação com um módulo de servidor e produz o contêiner reconhecido pela hidratação do WU.
renderApp(appName, options): Promise<RenderResult>
- Parâmetros: Nome não vazio; options.module obrigatório, props, styles, containerId, className, shadowMode e declarative; nonce opcional.
- Retorno: Objeto com html, inner, containerAttrs, state, appName e containerId.
- Erros: Propaga erros de entrada ou do renderizador; trate a rejeição antes de emitir a resposta HTTP.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { renderApp, renderHtml, escapeHtml } from 'wu-framework/server';
const card = renderHtml(({ title }) => `<h2>${escapeHtml(title)}</h2>`);
const result = await renderApp('card', { module: card, props: { title: 'Resumen' } });
console.log(result.html);
O módulo deve produzir HTML confiável. O helper escapa atributos e estado, mas não sanitiza o HTML retornado por render. Não importa automaticamente uma URL de navegador.
Referência: src/server/wu-server-render.js.
renderApps
Renderiza uma lista em paralelo e reúne HTML, estado e erros por aplicação.
renderApps(apps, options?): Promise<RenderAppsResult>
- Parâmetros: Lista de {name, module, …opciones}; failFast false por padrão; nonce compartilhado opcional.
- Retorno: {html, byApp, state, errors}; com failFast false, mantém resultados parciais.
- Erros: Por padrão, registra erros por entrada; failFast:true rejeita a operação. Não cancela renderizadores que já estão em execução.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { renderApps, renderHtml } from 'wu-framework/server';
const result = await renderApps([
{ name: 'summary', module: renderHtml(() => '<p>Resumen</p>') },
{ name: 'activity', module: renderHtml(() => '<p>Actividad</p>') },
]);
console.log(result.errors);
Referência: src/server/wu-server-render.js.
renderStateScript
Serializa o estado em um script que o cliente pode recuperar durante a hidratação.
renderStateScript(state, options?): string
- Parâmetros: state serializável; varName identificador JavaScript, merge boolean, nonce opcional.
- Retorno: Tag script completa.
- Erros: Rejeita varName inválido, nonce inválido ou valores que JSON.stringify não possa serializar.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { renderStateScript } from 'wu-framework/server';
const script = renderStateScript({ card: { title: 'Resumen' } }, { merge: true });
Não inclua segredos: esse estado é visível no HTML da resposta.
Referência: src/server/wu-server-render.js.
declarativeShadowDomPolyfill
Gera um script de compatibilidade para templates com shadowrootmode quando não há suporte nativo.
declarativeShadowDomPolyfill(options?): string
- Parâmetros: options.nonce opcional.
- Retorno: HTML de um script; não o executa ao chamar o helper.
- Erros: Um nonce inválido falha na construção do atributo.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { declarativeShadowDomPolyfill } from 'wu-framework/server';
const script = declarativeShadowDomPolyfill({ nonce });
Emita o script depois do conteúdo que deve converter; ele não observa templates futuros.
Referência: src/server/wu-server-render.js.
escapeHtml
Escapa ampersand, sinais de tag e aspas para texto ou atributos HTML.
escapeHtml(value): string
- Parâmetros: Qualquer valor; null e undefined são convertidos em string vazia.
- Retorno: String escapada.
- Erros: A coerção para string pode propagar um erro do próprio valor.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { escapeHtml } from 'wu-framework/server';
escapeHtml('<etiqueta>'); // '<etiqueta>'
Não valida URLs nem transforma HTML arbitrário em conteúdo seguro.
Referência: src/server/wu-server-render.js.
serializeState
Codifica JSON e impede o fechamento do script por caracteres de tag.
serializeState(value): string
- Parâmetros: Valor compatível com JSON; null/undefined na raiz são representados como null.
- Retorno: JSON com <, > e separadores Unicode escapados.
- Erros: Referências cíclicas, BigInt ou serializações não aceitas podem lançar erro.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { serializeState } from 'wu-framework/server';
serializeState({ title: '</script>' });
Referência: src/server/wu-server-render.js.
SSR_MARKER_ATTR / SSR_ROOT_ATTR
Expõe os nomes dos atributos que coordenam renderizador e hidratação.
SSR_MARKER_ATTR: 'data-wu-ssr'; SSR_ROOT_ATTR: 'data-wu-root'
- Parâmetros: Constantes exportadas de wu-framework/server.
- Retorno: Duas strings.
- Erros: A leitura das constantes não valida o conteúdo do contêiner.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { SSR_MARKER_ATTR, SSR_ROOT_ATTR } from 'wu-framework/server';
console.log(SSR_MARKER_ATTR, SSR_ROOT_ATTR);
Referência: src/server/wu-server-render.js.
createNonce
Gera um nonce de 128 bits com crypto.getRandomValues.
createNonce(): string
- Parâmetros: Sem parâmetros.
- Retorno: String base64url sem padding.
- Erros: Precisa de Web Crypto; lança erro se não estiver disponível.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { createNonce } from 'wu-framework/server';
const nonce = createNonce();
Referência: src/server/wu-security-headers.js.
buildCsp
Compõe uma política CSP para scripts, estilos, imagens, conexões e frames.
buildCsp(options?): string
- Parâmetros: nonce; listas scriptSrc/styleSrc/connectSrc/imgSrc/frameSrc; unsafeInlineStyle; https true por padrão.
- Retorno: Valor completo de Content-Security-Policy.
- Erros: Rejeita um nonce inválido; as listas de origens devem vir de configuração confiável.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { buildCsp } from 'wu-framework/server';
const policy = buildCsp({ nonce, connectSrc: ['https://api.example.com'] });
Sem nonce e sem styleSrc, a política inclui unsafe-inline para estilos; connect-src também incorpora scriptSrc. https:false omite upgrade-insecure-requests.
Referência: src/server/wu-security-headers.js.
securityHeaders
Constrói cabeçalhos CSP, HSTS, X-Frame-Options, MIME, referrer, permissions e CORS opcional.
securityHeaders(options?): Record<string, string>
- Parâmetros: Opções CSP mais hsts, frameOptions, referrerPolicy, permissionsPolicy, nosniff, corsOrigin e csp.
- Retorno: Mapa de cabeçalhos; não modifica uma resposta.
- Erros: Propaga a validação de CSP quando a política é gerada.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { securityHeaders } from 'wu-framework/server';
const headers = securityHeaders({ nonce, hsts: false, corsOrigin: 'https://shell.example.com' });
HSTS está ativo por padrão; desative-o explicitamente para uma resposta HTTP de desenvolvimento. csp:false omite CSP.
Referência: src/server/wu-security-headers.js.
applySecurityHeaders
Aplica os cabeçalhos a uma resposta Node compatível com setHeader.
applySecurityHeaders(res, options?): response
- Parâmetros: res com setHeader; getHeader permite combinar um Vary existente.
- Retorno: A mesma resposta.
- Erros: Lança erro se res não tiver setHeader ou se a política for inválida.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { applySecurityHeaders } from 'wu-framework/server';
applySecurityHeaders(res, { nonce });
Referência: src/server/wu-security-headers.js.
wuSecurityMiddleware
Cria middleware de Express ou Connect com nonce por solicitação.
wuSecurityMiddleware(options?): middleware
- Parâmetros: Opções de cabeçalhos;
noncedeve ser uma função por requisição. Omiti-la gera um nonce novo automaticamente; uma string fixa é rejeitada ao construir o wrapper. - Retorno: Função (req,res,next) que escreve req.wuNonce e res.locals.nonce se locals existir.
- Erros: Erros de geração do nonce ou dos cabeçalhos são propagados ao executar o middleware.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { wuSecurityMiddleware } from 'wu-framework/server';
app.use(wuSecurityMiddleware());
Referência: src/server/wu-security-headers.js.
withSecurityHeaders
Envolve um handler Fetch e adiciona cabeçalhos, mantendo o corpo e o status HTTP.
withSecurityHeaders(handler, options?): (request) => Promise<Response>
- Parâmetros: handler(request,{nonce}) deve retornar Response.
- Retorno: Handler assíncrono com uma nova Response.
- Erros: Propaga o erro do handler e exige um resultado compatível com Response.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { withSecurityHeaders } from 'wu-framework/server';
const GET = withSecurityHeaders(async (_request, { nonce }) => {
return new Response(`<p>Listo</p>`, { headers: { 'Content-Type': 'text/html' } });
});
Referência: src/server/wu-security-headers.js.
renderReact
Adapta o renderizador do React ao contrato de renderApp.
renderReact(ComponentOrFn, options?): { render(props): Promise<RenderOutput> }
- Parâmetros: Component React; styles, strictMode, react e renderToString injetáveis.
- Retorno: Módulo de servidor com render que retorna html, styles e state.
- Erros: Propaga erros de entrada ou do renderizador; trate a rejeição antes de emitir a resposta HTTP.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { renderReact, renderApp } from 'wu-framework/server';
import React from 'react';
import { renderToString } from 'react-dom/server';
const module = renderReact(Card, { react: React, renderToString });
const result = await renderApp('card', { module, props: { count: 2 } });
Injete a mesma instância do React usada pelo componente para evitar duplicar seu runtime.
Referência: src/server/adapters.js.
renderVue
Adapta o renderizador do Vue ao contrato de renderApp.
renderVue(ComponentOrFn, options?): { render(props): Promise<RenderOutput> }
- Parâmetros: Component Vue; styles, setup(app,props), createSSRApp e renderToString injetáveis.
- Retorno: Módulo de servidor com render que retorna html, styles e state.
- Erros: Propaga erros de entrada ou do renderizador; trate a rejeição antes de emitir a resposta HTTP.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { renderVue, renderApp } from 'wu-framework/server';
const module = renderVue(Card, { setup(app) { /* app.use(plugin) */ } });
const result = await renderApp('card', { module, props: { count: 2 } });
Precisa de vue e @vue/server-renderer ou de ambas as funções injetadas.
Referência: src/server/adapters.js.
renderPreact
Adapta o renderizador do Preact ao contrato de renderApp.
renderPreact(ComponentOrFn, options?): { render(props): Promise<RenderOutput> }
- Parâmetros: Component Preact; styles, h e renderToString injetáveis.
- Retorno: Módulo de servidor com render que retorna html, styles e state.
- Erros: Propaga erros de entrada ou do renderizador; trate a rejeição antes de emitir a resposta HTTP.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { renderPreact, renderApp } from 'wu-framework/server';
const module = renderPreact(Card, { styles: ['h2{color:navy}'] });
const result = await renderApp('card', { module, props: { count: 2 } });
Precisa de preact e preact-render-to-string se as funções não forem injetadas.
Referência: src/server/adapters.js.
renderSvelte
Adapta o renderizador do Svelte ao contrato de renderApp.
renderSvelte(ComponentOrFn, options?): { render(props): Promise<RenderOutput> }
- Parâmetros: Componente compilado para servidor e styles opcionais.
- Retorno: Módulo de servidor com render que retorna html, styles e state.
- Erros: Propaga erros de entrada ou do renderizador; trate a rejeição antes de emitir a resposta HTTP.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { renderSvelte, renderApp } from 'wu-framework/server';
const module = renderSvelte(Card);
const result = await renderApp('card', { module, props: { count: 2 } });
Svelte 4 usa Component.render; Svelte 5 importa svelte/server. O wrapper não adiciona out.head ao documento.
Referência: src/server/adapters.js.
renderSolid
Adapta o renderizador do Solid ao contrato de renderApp.
renderSolid(ComponentOrFn, options?): { render(props): Promise<RenderOutput> }
- Parâmetros: Componente compilado para SSR e styles opcionais.
- Retorno: Módulo de servidor com render que retorna html, styles e state.
- Erros: Propaga erros de entrada ou do renderizador; trate a rejeição antes de emitir a resposta HTTP.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { renderSolid, renderApp } from 'wu-framework/server';
const module = renderSolid(Card);
const result = await renderApp('card', { module, props: { count: 2 } });
Resolve solid-js/web no ambiente servidor; não aceita um renderizador injetado como React.
Referência: src/server/adapters.js.
renderHtml
Adapta o renderizador de Html ao contrato de renderApp.
renderHtml(ComponentOrFn, options?): { render(props): Promise<RenderOutput> }
- Parâmetros: Função (props) => string|Promise
e styles string/lista/função. - Retorno: Módulo de servidor com render que retorna html, styles e state.
- Erros: Propaga erros de entrada ou do renderizador; trate a rejeição antes de emitir a resposta HTTP.
- Permissões: Não usa concessões do navegador; a aplicação servidor controla módulos, dados e cabeçalhos.
- Limpeza: Não cria listeners nem um runtime cliente persistente.
import { renderHtml, renderApp } from 'wu-framework/server';
const module = renderHtml(({ count }) => `<p>${Number(count)}</p>`);
const result = await renderApp('card', { module, props: { count: 2 } });
O HTML retornado não é sanitizado. Escape o conteúdo externo antes de interpolá-lo.
Referência: src/server/adapters.js.
createServerRequest
createServerRequest(options?): WuServerRequest
Cria um contexto privado por requisição com signal, locals, renderApp, renderApps, stream e dispose. Aceita opções de lote, incluindo request, e combina seu sinal com options.signal. Não crie esse objeto no escopo global do módulo. dispose(reason) aborta, libera listeners e limpa locals.
import { createServerRequest, renderStateScript, escapeHtml, withSecurityHeaders } from 'wu-framework/server';
export const GET = withSecurityHeaders(async (request, { nonce }) => {
const scope = createServerRequest({ request, nonce, timeout: 2000, concurrency: 2 });
try {
scope.locals.set('requestId', crypto.randomUUID());
const rendered = await scope.renderApps([{
name: 'greeting',
load: async ({ signal }) => {
signal.throwIfAborted();
return { props: { label: 'Hello' }, publicState: { label: 'Hello' } };
},
module: { render: props => '<p>' + escapeHtml(props.label) + '</p>' },
}]);
return new Response(rendered.html + renderStateScript(rendered.state, { nonce }), {
headers: { 'Content-Type': 'text/html; charset=utf-8' },
});
} finally {
scope.dispose();
}
});
load(context) recebe { appName, signal, request, locals } e retorna { props?, publicState? }. Com loader, apenas publicState vira estado de hidratação; nem props privadas nem o state retornado pelo renderer são publicados automaticamente. Sem loader, o state do renderer é preservado. Isso não impede o próprio renderer de escrever um segredo no HTML.
Cancelamento, prazos e concorrência SSR
renderApp, renderApps e renderAppsStream aceitam signal e timeout por app, incluindo o loader; timeout: 0 desativa o prazo. Lotes e streams aceitam concurrency, ilimitada por padrão. O aborto preserva signal.reason; sem motivo fornecido usa WU_SSR_ABORTED. Vencer o prazo produz WU_SSR_TIMEOUT. Renderers e loaders devem cooperar com context.signal para parar seu trabalho.
Sem failFast, uma falha de app permite degradação parcial; com failFast: true, o lote é abortado. Cancelar o stream propaga o aborto ao trabalho pendente. Ao retornar um stream HTTP, mantenha o contexto até o consumo terminar ou ser cancelado; não chame dispose() logo após construir a resposta.
// Reusable wrappers: a function generates a new nonce for each request.
wuSecurityMiddleware({ nonce: () => createNonce() });
withSecurityHeaders(handler, { nonce: () => createNonce() });
// Low-level helpers still accept the nonce of this response.
const nonce = createNonce();
const headers = securityHeaders({ nonce });