WU / DOCSMICROFRONTENDS UNIVERSAIS
PT

SSR e hidratação

Contrato render do servidor, Declarative Shadow DOM, estado de hidratação e helpers React/Vue.

Veja versões, mudanças e requisitos em Framework 4.0 e CLI 1.2.

O que o servidor produz

wu-framework/server transforma o resultado de um renderizador no HTML de um contêiner WU. Por padrão, encapsula conteúdo e estilos em Declarative Shadow DOM. O navegador pode materializar essa árvore antes de o JavaScript da app carregar.

O servidor recebe um módulo com render(props), não o ciclo de vida de montagem do cliente. O resultado pode ser uma string HTML ou { html, styles?, state? }. Quem gera o HTML deve escapar os dados não confiáveis antes de incorporá-los.

import { renderApp, escapeHtml, renderStateScript } from 'wu-framework/server';

const result = await renderApp('greeting', {
  props: { name: 'Ada' },
  module: {
    render(props) {
      return {
        html: `<p>Hola, ${escapeHtml(props.name)}</p>`,
        styles: 'p { color: #f97316; }',
        state: props,
      };
    },
  },
});

const html = result.html + renderStateScript({ greeting: result.state });

renderApp também aceita um módulo já importado, uma promise, um módulo default ou uma função que o carrega. O host decide quais módulos pode executar no servidor; não transforme uma entrada do usuário em um import arbitrário.

Resultado e opções

Elemento Contrato
result.html Contêiner completo
result.inner Interior declarativo ou plano
result.containerAttrs ID, data-wu-app, data-wu-ssr, classe opcional
result.state Estado opcional retornado pelo renderizador
containerId Por padrão, wu-app-<name>
shadowMode open por padrão; closed impede a hidratação normal
declarative true por padrão
styles CSS extra do host para essa app
nonce Nonce CSP para estilos dessa resposta

renderApps processa várias apps em paralelo. Por padrão, registra falhas individuais em errors e mantém as outras; failFast: true permite abortar. Um renderizador que falha em renderApp produz um erro com código WU_SSR_RENDER_FAILED.

Hidratar sem apagar

No cliente, o shell registra a app normalmente e a monta no contêiner SSR. O sandbox detecta data-wu-ssr e a raiz data-wu-root. Se existir lifecycle.hydrate, o core o invoca com as props do servidor e a fachada com escopo. Sem esse slot, chama mount e o HTML anterior funciona como conteúdo inicial até o renderizador substituí-lo.

wu.define('greeting', {
  mount(container) {
    container.textContent = 'Montaje cliente';
  },
  hydrate(container, { props }) {
    // Adoptar lo que ya existe. No limpiar container primero.
    const paragraph = container.querySelector('p');
    paragraph?.setAttribute('aria-label', `Saludo para ${props.name}`);
  },
  unmount(container) {
    container.replaceChildren();
  },
});

No React, hydrateRoot deve receber a mesma árvore e props produzidas pelo servidor. No Vue, o adaptador usa createSSRApp e .mount para adotar o DOM existente. O estado publicado deve manter essa correspondência; alterar dados entre renderização e hidratação causa divergências.

Helpers de renderizador

O subcaminho server exporta renderReact, renderPreact, renderVue, renderSvelte, renderSolid e renderHtml. Os helpers retornam um módulo conforme o contrato render.

import * as React from 'react';
import { renderToString } from 'react-dom/server';
import { renderReact } from 'wu-framework/server';
import App from './App.jsx';

export default renderReact(App, {
  react: React,
  renderToString,
  styles: '.greeting { font-weight: 600; }',
});

Injetar renderizador e runtime evita resolver outra cópia do React fora do bundle do servidor. Vue aceita a injeção de createSSRApp e renderToString, além de setup. Os nomes das opções do servidor não são idênticos a runtime: { React, ReactDOM } do adaptador cliente.

Astro

---
import WuAppSSR from 'wu-framework/integrations/astro/WuAppSSR.astro';
import greetingServer from '../apps/greeting/server.js';
---
<WuAppSSR
  name="greeting"
  module={greetingServer}
  props={{ name: 'Ada' }}
  fallbackToClient={false}
/>

O shell ainda deve inicializar o registro cliente correspondente. O componente publica estado como JSON para hidratar; hydrate é true por padrão. fallbackToClient também é true: uma falha SSR deixa o slot para uma montagem cliente, a menos que você desative isso, como no exemplo.

Em um build estático do Astro, o renderizador é executado na compilação; isso não transforma a página em conteúdo personalizado por solicitação. Para dados dependentes do usuário, você precisa de uma estratégia adequada de servidor ou carregamento cliente.

Estado e cabeçalhos

serializeState e renderStateScript resolvem a serialização para o contexto HTML/script. escapeHtml escapa texto, não valida uma aplicação HTML arbitrária. Não injete segredos no estado de hidratação: tudo o que é publicado nessa página fica visível para seu leitor.

createNonce() produz um nonce para uma resposta. securityHeaders, applySecurityHeaders, wuSecurityMiddleware e withSecurityHeaders ajudam a instalar CSP e outros cabeçalhos. Use o mesmo nonce da resposta nos estilos/scripts que devem ser executados e um novo nonce na próxima resposta; o servidor controla essa coordenação.

Referência de implementação

Exportações: src/server/index.js; render: src/server/wu-server-render.js; múltiplas renderizações: src/server/wu-server-render.js; tipos: src/server/index.d.ts; adoção do DOM: src/core/wu-sandbox.js; slot hydrate: src/core/wu-core.js; Astro: integrations/astro/WuAppSSR.astro. Testes: tests/unit/server-render.test.js, tests/unit/server-security-fuzz.test.js, tests/unit/security-headers.test.js.

Para isolar cada requisição e limitar trabalho, consulte createServerRequest, loaders privados, cancelamento e concorrência na referência SSR. Os wrappers de cabeçalhos 4.0 rejeitam um nonce fixo: use uma função por requisição ou a geração padrão.

CONSTRUA O WU CONOSCO

Encontrou um bug? Tem uma ideia?

Sua experiência melhora o WU. Conte o que falhou ou ajude a manter seu desenvolvimento.