Volver a Casos de Ingeniería
Hablemos de un Desafío Similar
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 unIntersectionObserver. - Sustitución de Google Fonts
@importpor<link rel="preload">confont-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:
-140msde 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