Back to Engineering Cases
December 21, 2024

Achieving 100/100 Core Web Vitals on a Laravel SaaS

Conversion rate +18%, Bounce rate -22%

Laravel MySQL Varnish Redis CloudFront CDN Tailwind CSS Alpine.js

The Bottleneck

A B2B SaaS dashboard with real-time analytics was scoring 34/100 on Lighthouse Mobile. The PageSpeed Insights lab data showed: LCP at 6.8s, TBT at 1,240ms, CLS at 0.45. Users on 4G connections in rural areas were abandoning before the page even loaded. The cause wasn't a single smoking gun, but a death by a thousand cuts:

  • Laravel Mix + Webpack producing 2.1MB of uncompressed JS
  • No static asset caching strategy (Cache-Control headers missing)
  • Database queries on every page load for unchanging config data
  • Google Fonts blocking render via @import
  • Chart.js loading synchronously in <head>
  • No resource hints (preconnect, preload, dns-prefetch)

Architecture & Automation

I executed a systematic WPO overhaul across every layer of the stack:

Frontend

  • Migrated from Laravel Mix to Vite 5 with code splitting: -68% JS bundle size
  • Replaced Chart.js synchronous load with dynamic import() gated on IntersectionObserver
  • Swapped Google Fonts @import for <link rel="preload"> with font-display: swap
  • Replaced 60KB of FontAwesome CDN with 3 inline SVGs (total: 2KB)
  • Added <link rel="preconnect"> for CDN origins

Backend

  • Varnish Cache in front of Laravel: full-page caching with ESI for dynamic widgets
  • Redis for config/session data: -140ms TTFB on 95th percentile
  • Lazy-load all below-fold content: controllers configured to defer non-critical DB queries
  • Cache warming on deploy: GitHub Actions step hits critical routes post-deploy

CDN & Headers

  • All static assets served via CloudFront CDN with immutable Cache-Control: public, max-age=31536000
  • HTML responses: Cache-Control: public, s-maxage=3600, stale-while-revalidate=86400

Measurable ROI

  • Lighthouse Mobile: 34 → 100 (Performance), 100 (Accessibility), 100 (Best Practices), 100 (SEO)
  • LCP: 6.8s → 1.2s (-82%)
  • TBT: 1,240ms → 0ms (-100%)
  • CLS: 0.45 → 0.00 (zero layout shift)
  • Conversion rate: +18% (form submissions)
  • Bounce rate: -22% (from 68% to 53%)
  • Page weight: 2.8MB → 340KB (-88%)

Written by

Miguel Ortiz

Growth Engineer & Technical SEO

Discuss a Similar Challenge