¿Qué es la hydration? El paso que vuelve interactivo el HTML renderizado en el servidor

  • vuetelemetry
  • Guías
  • 7 min de lectura

El HTML renderizado en el servidor es inerte hasta que la hydration le conecta Vue. Qué hace la hydration, por qué importa createSSRApp, las tres causas documentadas de un mismatch de hydration y por qué un mismatch es un impuesto silencioso sobre el rendimiento y no un fallo.

El renderizado en el servidor entrega un HTML ya completo antes de que se ejecute cualquier JavaScript, y por eso ayuda al primer pintado y a los rastreadores. Pero ese HTML es inerte. La propia documentación de Vue lo dice con claridad: si pulsas el botón, el número no cambia, porque la página es estática hasta que el framework toma el relevo en el navegador. La hydration es ese relevo.

Vue describe el mecanismo con precisión. Durante la hydration crea la misma aplicación Vue que se ejecutó en el servidor, asocia cada componente con los nodos del DOM que debe controlar y conecta los escuchadores de eventos del DOM. Cuando todo va bien no se reconstruye nada desde cero: el marcado ya está ahí y la hydration se apropia de él.

Hay que pedirlo de forma explícita, no ocurre solo. Montar en el cliente una aplicación renderizada en el servidor requiere createSSRApp y no createApp, porque eso le indica a Vue que el HTML venía pre-renderizado y que debe hidratarlo en lugar de montar nodos DOM nuevos. Equivocarse de función es una manera habitual de renderizarlo todo dos veces sin darse cuenta.

Cuando las dos versiones no coinciden

Panel del inspector de un navegador mostrando un árbol DOM de elementos div y header anidados. Un mismatch de hydration es una discrepancia entre este árbol y lo que espera la aplicación del lado del cliente.
Panel del inspector de un navegador mostrando un árbol DOM de elementos div y header anidados. Un mismatch de hydration es una discrepancia entre este árbol y lo que espera la aplicación del lado del cliente.

Todo esto da por hecho que la salida del servidor y lo que espera el cliente coinciden. Cuando no coinciden aparece un mismatch de hydration, que Vue define como que la estructura del DOM del HTML pre-renderizado no coincide con la salida esperada por la aplicación del lado del cliente.

La documentación nombra tres causas, y ninguna es exótica.

Las tres causas documentadas

La primera es el anidamiento HTML inválido. Si una plantilla coloca un div dentro de un p, el propio analizador del navegador corrige la estructura mientras lee el HTML del servidor, y el DOM ya corregido deja de coincidir con lo que espera el cliente. El framework no hizo nada mal: el navegador reescribió la página antes de que Vue llegara a verla.

  • La hydration recrea en el navegador la aplicación ejecutada en el servidor, asocia los componentes a los nodos del DOM existentes y conecta los escuchadores de eventos.
  • Requiere createSSRApp en lugar de createApp, lo que le indica a Vue que hidrate en vez de montar nodos nuevos.
  • Un mismatch de hydration es cuando el DOM pre-renderizado no coincide con lo que espera la aplicación del lado del cliente.
  • Vue nombra tres causas: anidamiento HTML inválido corregido por el analizador del navegador, valores generados aleatoriamente y zonas horarias distintas entre servidor y cliente.
  • Vue se recupera automáticamente y la aplicación sigue funcionando, pero los nodos descartados y vueltos a montar cuestan rendimiento de renderizado.

La segunda son los valores generados aleatoriamente. La misma aplicación se ejecuta dos veces, una en el servidor y otra en el navegador, y nada garantiza que un valor aleatorio sea idéntico entre esas dos ejecuciones. Cualquier cosa sorteada en el momento del render terminará divergiendo.

La tercera son las zonas horarias. Cuando el servidor y el cliente están en zonas distintas, una fecha formateada durante la ejecución en el servidor y esa misma fecha formateada en el navegador no coincidirán. Es la causa que más tiempo sobrevive en producción, porque solo aparece para los usuarios que están en el lugar equivocado.

Por que es un coste silencioso

Lo que ocurre después explica por qué este fallo es tan fácil de pasar por alto. Vue intenta recuperarse automáticamente y ajusta el DOM pre-renderizado para que encaje con el estado del cliente, de modo que la aplicación en general sigue funcionando. El precio es una pérdida de rendimiento de renderizado, porque los nodos incorrectos se descartan y en su lugar se montan otros nuevos.

Un mismatch, por tanto, rara vez es un fallo total. Es un impuesto silencioso: el servidor produjo HTML y luego parte de ese trabajo se tiró y se rehízo en el navegador. Pagaste el renderizado en el servidor dos veces y te quedaste con el beneficio una sola. Es justo el tipo de regresión que una prueba funcional nunca detecta, porque la página sigue viéndose bien.

Un mismatch, por tanto, rara vez es un fallo total. Es un impuesto silencioso: el servidor produjo HTML y luego parte de ese trabajo se tiró y se rehízo en el navegador. Pagaste el renderizado en el servidor dos veces y te quedaste con el beneficio una sola. Es justo el tipo de regresión que una prueba funcional nunca detecta, porque la página sigue viéndose bien.

- vuetelemetry

La respuesta mas simple para paginas estaticas

Si los datos necesarios para renderizar una página son los mismos para todos los usuarios, Vue apunta a una respuesta más sencilla que renderizar en cada petición: la generación de sitios estáticos, también llamada pre-renderizado, donde la página se renderiza una sola vez durante el build. La hydration sigue aplicándose al resultado, pero el coste de servidor por petición desaparece. Antes de optimizar una canalización SSR, conviene preguntarse si la página necesitaba ser dinámica.

Stack relacionado