Hidratación
La hidratación es el momento en que el cliente adopta el marcado que el servidor ya pintó, en vez de tirarlo y volver a renderizar. En wu es un slot del ciclo de vida, no una API aparte.
Qué hace mount() de forma distinta
Sección titulada «Qué hace mount() de forma distinta»wu.mount('cart', '#wu-app-cart') es la misma llamada tanto si la página se renderizó en servidor como si no. Por dentro, el sandbox ejecuta _detectSsrRoot(hostContainer):
- Si el contenedor no tiene el atributo
data-wu-ssr→ montaje normal, no cambia nada. - Si el navegador ya materializó el Declarative Shadow DOM (existe
hostContainer.shadowRoot) → busca[data-wu-root]dentro y lo reutiliza. - Si el
<template shadowrootmode>sigue en el light DOM (navegador sin DSD nativo y sin polyfill en la página) →attachShadow(), mueve el contenido del template dentro, elimina el template y continúa como si hubiera sido nativo.
Cuando encuentra una raíz del servidor, wu no la limpia. Marca el elemento [data-wu-root] existente como contenedor de la app, inserta sus estilos base antes del marcado del servidor (para no alterar el orden de pintado) y activa isHydration en el sandbox.
Luego wu-core elige el slot:
const hydrating = sandbox.isHydration && typeof lifecycle.hydrate === 'function';if (hydrating) { await lifecycle.hydrate(sandbox.container, { appName, props: this._ssrProps(appName) });} else { await lifecycle.mount(sandbox.container);}_ssrProps(appName) lee window.__WU_SSR_STATE__[appName] y recurre a {} si el script falta o no se puede leer. El registro de la app montada lleva hydrated: true para que los diagnósticos distingan ambos caminos.
El slot hydrate
Sección titulada «El slot hydrate»hydrate(container: HTMLElement, ctx: { appName: string; props: Record<string, any> }): void | Promise<void>Escrito a mano:
wu.define('cart', { mount(container) { container.innerHTML = render(state); wireEvents(container); },
// Se llama solo cuando el contenedor vino de wu-framework/server hydrate(container, { props }) { // El DOM ya es correcto: basta con conectar el comportamiento wireEvents(container); },
unmount(container) { container.innerHTML = ''; },});Los adaptadores lo conectan por ti donde el framework lo soporta:
| Adaptador | hydrate |
Cómo |
|---|---|---|
| React | sí | hydrateRoot: se engancha al DOM existente |
| Vue | sí | createSSRApp: hidrata en vez de montar |
| Preact, Svelte, Solid y el resto | no | recurre a mount sobre el marcado del servidor |
Llevar las props al cliente
Sección titulada «Llevar las props al cliente»Tres formas, un mismo destino: window.__WU_SSR_STATE__.
// 1. Un shell sencillores.end(template.replace('<!--state-->', renderStateScript(state)));// 2. Next: WuMount las publica en un efecto antes de llamar a wu.mount()<WuAppSSR name="cart" module={cartServer} props={{ userId: 42 }} /><!-- 3. Astro: se emite un <script type="application/json" data-wu-ssr-state="cart"> por app, y lo lee el script de hidratación empaquetado --><WuAppSSR name="cart" module={cartServer} props={{ userId: 42 }} />Ambas integraciones se fusionan con el objeto existente en vez de reemplazarlo, así que varias instancias de WuAppSSR conviven en una misma página.
Orden respecto a la hidratación del propio shell
Sección titulada «Orden respecto a la hidratación del propio shell»En Next, WuMount se ejecuta en un useEffect, es decir después de que React haya hidratado la página. Publica las props, importa wu-framework dinámicamente y llama a wu.mount(name, '#' + containerId). Si el efecto se limpia mientras el montaje sigue en vuelo, desmonta la app, de modo que una navegación rápida no puede dejar una app enganchada a un contenedor desprendido.
En Astro, el <script> empaquetado consulta cada div[data-wu-app][data-wu-hydrate="true"] y los monta al cargar.
Cosas que impiden la hidratación
Sección titulada «Cosas que impiden la hidratación»| Situación | Resultado |
|---|---|
shadowMode: 'closed' |
El cliente no puede leer hostContainer.shadowRoot, así que no se detecta ninguna raíz: la app se monta desde cero. Usa closed solo para marcado inerte. |
declarative: false |
Marcado plano, sin shadow root, data-wu-ssr="flat". La detección no encuentra ningún [data-wu-root] dentro de un shadow root → montaje normal. |
| El render de la app lanzó un error | renderApps emitió un contenedor vacío sin data-wu-ssr → montaje normal. Esa es la degradación prevista. |
Falta el slot hydrate |
Monta encima del marcado y escribe una línea de depuración. |
| Props que no coinciden | Nadie lo detecta. Lo que haya en window.__WU_SSR_STATE__[appName] es lo que recibe hydrate; si el servidor renderizó con otros datos, React o Vue avisarán o parchearán, exactamente como en cualquier montaje SSR. |
Depuración
Sección titulada «Depuración»- Haz
curla la página. Si no vesdata-wu-ssr="open"y un<template shadowrootmode>, el problema está en el servidor, no en la hidratación. - En DevTools, el contenedor debería mostrar
#shadow-root (open)con<div data-wu-root data-wu-hydrated="true">dentro. - Activa el registro de depuración de wu: los caminos de hidratación emiten
SSR markup detected for <app> — hydrating in place, o bien<app> has server markup but no hydrate() slot — mounting over it.
