Saltar al contenido

Arquitectura Base: MPA con vite-ssg

Este es un análisis de la arquitectura implementada en un proyecto privado interno, que combina vite-ssg para la generación de sitios estáticos con un backend de Nitro (en el trabajo, Kotlin con Spring Boot). El objetivo es crear una aplicación web de alto rendimiento que se sienta instantánea para los usuarios, incluso en redes lentas.

Resumen Ejecutivo

La arquitectura implementada transforma el concepto tradicional de Aplicación de Página Única (SPA/CSR) en una MPA (Aplicación Multi-Página) con superpoderes. Aprovechando una build estática con vite-ssg, se genera una base de HTML ultrarrápida. Un backend de Nitro personalizado intercepta las peticiones para "enriquecer" este HTML estático con un estado dinámico antes de servirlo. En el cliente, la aplicación se hidrata usando este estado inyectado, eliminando la necesidad de llamadas iniciales al API desde el cliente. El resultado es una carga inicial casi instantánea, característica de una MPA, combinada con una navegación fluida en el lado del cliente, característica de una SPA, gracias a vue-router.

El Flujo de Renderizado y Carga

El proceso se divide en tres fases clave:

1. Tiempo de Build (SSG)

  • Generación Estática: vite-ssg pre-renderiza las páginas en ficheros HTML planos.
  • Estado de Carga Inicial: El HTML estático incluye un indicador de carga (ej. una barra de progreso) visible por defecto, ya que el estado inicial isReady de la aplicación es false en el momento del build.
  • Optimización de Assets: Todos los assets se generan y optimizan: CSS crítico (beasties), fallbacks de fuentes compatibles con las métricas para prevenir CLS (fontless), y versiones pre-comprimidas (.gz, .br) de los ficheros JS/CSS.

2. Petición de Página (Lado del Servidor - Nitro)

  • Intercepción: Una petición de un usuario (ej. a /alguna-pagina) es capturada por un middleware de Nitro.
  • Obtención de Datos: El handler de Nitro ejecuta la lógica de negocio necesaria en el servidor. Esto incluye, por ejemplo, verificar la sesión del usuario y obtener los datos de la página desde la base de datos.
  • Inyección de Estado: Los datos obtenidos se recolectan, se serializan en un objeto JSON, y se inyectan en el HTML estático (leído desde el disco) dentro de una etiqueta <script>, típicamente window.__INITIAL_STATE__.
  • Entrega Optimizada: El servidor envía el HTML "enriquecido" al navegador, junto con cabeceras Link: rel=preload para los assets críticos.

3. Hidratación (Lado del Cliente - Vue)

  • Renderizado Instantáneo: El navegador recibe el HTML e inmediatamente muestra la estructura de la página y el indicador de carga. El LCP es extremadamente rápido. Este es un nivel magistral de optimización de la performance percibida. Nos adelantamos al LCP y al INP, y optimizamos para el Time to First Meaningful Paint y la sensación de velocidad del usuario.
  • Lógica de Hidratación Resiliente:
    • La aplicación de Vue se hidrata. El store de estado (ej. Pinia) se inicializa y comprueba la existencia de window.__INITIAL_STATE__.
    • Caso Feliz: Si __INITIAL_STATE__ existe, el store se puebla con estos datos de forma síncrona. La condición isReady se cumple, los componentes renderizan los datos y el indicador de carga desaparece. No hay un viaje de ida y vuelta al API en el cliente.
    • Caso de Fallback: Si la inyección de estado falló por cualquier motivo y __INITIAL_STATE__ no se encuentra, el store detecta su ausencia y dispara una llamada fetch al API del backend para obtener los datos. La aplicación se comporta entonces como una SPA tradicional, garantizando la funcionalidad en todo momento.

Principios y Beneficios Clave

Esta arquitectura combina múltiples estrategias para lograr un resultado de élite:

  • Rendimiento de Carga Extremo: Consigue un TTFB y LCP mínimos al servir un fichero estático enriquecido y precargar los assets críticos.
  • Hidratación Eficiente (Sin Roundtrip): Eliminar la primera llamada al API desde el cliente es la mayor optimización de rendimiento para una aplicación rica de datos.
  • Resiliencia: El mecanismo de fallback a fetch asegura que la aplicación siga siendo funcional incluso si el proceso de inyección en el servidor falla.
  • Arquitectura Híbrida ("MPA con Superpoderes"): Ofrece los beneficios de una MPA (carga inicial instantánea) y de una SPA (navegación fluida en el cliente sin recargas de página), creando una experiencia de usuario de primera clase.

Liberado bajo la licencia MIT