Volver a Casos de Ingeniería
21 de diciembre de 2024

Logrando 100/100 Core Web Vitals en un SaaS Laravel

Tasa de conversión +18%, Tasa de rebote -22%

Laravel MySQL Varnish Redis CloudFront CDN Tailwind CSS Alpine.js

El Cuello de Botella

Un panel de control SaaS B2B con análisis en tiempo real obtenía una puntuación de 34/100 en Lighthouse Móvil. Los datos de laboratorio de PageSpeed Insights mostraban: LCP a 6.8s, TBT a 1.240ms, y CLS a 0.45. Los usuarios con conexiones 4G en zonas rurales abandonaban el sitio antes de que la página terminara de cargar. La causa no era un único fallo grave, sino una suma de múltiples ineficiencias acumuladas:

  • Laravel Mix + Webpack producían 2.1 MB de JS sin comprimir
  • No existía estrategia de almacenamiento en caché para recursos estáticos (faltaban cabeceras Cache-Control)
  • Consultas a la base de datos en cada carga de página para datos de configuración estáticos
  • Google Fonts bloqueaba el renderizado mediante @import
  • Chart.js se cargaba de forma síncrona en el <head>
  • No se utilizaban sugerencias de recursos (preconnect, preload, dns-prefetch)

Arquitectura y Automatización

Ejecuté una optimización sistemática de rendimiento web (WPO) en todas las capas del ecosistema:

Frontend

  • Migración de Laravel Mix a Vite 5 con separación de código: -68% de reducción en el tamaño del bundle JS.
  • Reemplazo de la carga síncrona de Chart.js por import() dinámico activado mediante un IntersectionObserver.
  • Sustitución de Google Fonts @import por <link rel="preload"> con font-display: swap.
  • Reemplazo de 60KB del CDN de FontAwesome por 3 archivos SVG integrados (total: 2KB).
  • Adición de <link rel="preconnect"> para los orígenes del CDN.

Backend

  • Caché Varnish frente a Laravel: almacenamiento en caché de página completa con ESI para widgets dinámicos.
  • Redis para datos de sesión e inicio: -140ms de TTFB en el percentil 95.
  • Carga diferida (lazy-load) de contenido secundario: controladores configurados para posponer consultas no críticas a la base de datos.
  • Precalentamiento de caché tras el despliegue: un paso de GitHub Actions accede a las rutas críticas después de cada subida.

CDN y Cabeceras

  • Todos los recursos estáticos servidos mediante CloudFront CDN con cabeceras inmutables Cache-Control: public, max-age=31536000.
  • Respuestas HTML: Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400.

ROI Medible

  • Lighthouse Móvil: 34 → 100 (Rendimiento), 100 (Accesibilidad), 100 (Buenas prácticas), 100 (SEO)
  • LCP: 6.8s → 1.2s (-82%)
  • TBT: 1.240ms → 0ms (-100%)
  • CLS: 0.45 → 0.00 (cero cambios inesperados de diseño)
  • Tasa de conversión: +18% (formularios enviados)
  • Tasa de rebote: -22% (pasó del 68% al 53%)
  • Peso de la página: 2.8MB → 340KB (-88%)

Escrito por

Miguel Ortiz

Growth Engineer & Technical SEO

Hablemos de un Desafío Similar