Web Performance Optimization: Complete 2024 Guide
Ultimate guide to web performance: Core Web Vitals, image optimization, code splitting, lazy loading, and advanced performance monitoring techniques.

Web performance directly impacts user experience, SEO rankings, and business metrics. This comprehensive guide covers everything you need to know about optimizing web performance in 2024.
Core Web Vitals
Google's Core Web Vitals are essential metrics for measuring user experience.
Largest Contentful Paint (LCP)
Target: < 2.5 seconds
// Optimize LCP with resource hints
<link rel="preload" href="/hero-image.jpg" as="image">
<link rel="dns-prefetch" href="//fonts.googleapis.com">
// Lazy load non-critical images
<img
src="placeholder.jpg"
data-src="hero-image.jpg"
loading="lazy"
alt="Hero image"
/>
First Input Delay (FID) / Interaction to Next Paint (INP)
Target: < 100ms / < 200ms
// Break up long tasks
function processLargeArray(items) {
const batchSize = 1000
let index = 0
function processBatch() {
const endIndex = Math.min(index + batchSize, items.length)
for (let i = index; i < endIndex; i++) {
// Process item
processItem(items[i])
}
index = endIndex
if (index < items.length) {
// Schedule next batch
setTimeout(processBatch, 0)
}
}
processBatch()
}
Cumulative Layout Shift (CLS)
Target: < 0.1
/* Reserve space for images */
.image-container {
aspect-ratio: 16 / 9;
background-color: #f0f0f0;
}
/* Use transform for animations */
.animated-element {
transform: translateY(0);
transition: transform 0.3s ease;
}
.animated-element:hover {
transform: translateY(-5px);
}
Image Optimization
Images often account for 50%+ of page weight. Here's how to optimize them:
Modern Formats
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Description" loading="lazy">
</picture>
Responsive Images
<img
srcset="small.jpg 320w, medium.jpg 768w, large.jpg 1200w"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
src="medium.jpg"
alt="Responsive image"
loading="lazy"
>
Next.js Image Optimization
import Image from 'next/image'
<Image
src="/hero.jpg"
alt="Hero image"
width={1200}
height={600}
priority // For above-the-fold images
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
/>
Code Splitting and Lazy Loading
Reduce initial bundle size with strategic code splitting.
Route-based Splitting
// React Router with lazy loading
import { lazy, Suspense } from 'react'
const Dashboard = lazy(() => import('./Dashboard'))
const Profile = lazy(() => import('./Profile'))
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/profile" element={<Profile />} />
</Routes>
</Suspense>
)
}
Component-based Splitting
// Dynamic imports with conditions
async function loadChart() {
if (window.innerWidth > 768) {
const { AdvancedChart } = await import('./AdvancedChart')
return AdvancedChart
} else {
const { SimpleChart } = await import('./SimpleChart')
return SimpleChart
}
}
Bundle Optimization
Analyze and optimize your JavaScript bundles.
Webpack Bundle Analyzer
npm install --save-dev webpack-bundle-analyzer
Tree Shaking
// Bad: Imports entire library
import _ from 'lodash'
// Good: Import only what you need
import debounce from 'lodash/debounce'
import throttle from 'lodash/throttle'
// Better: Use ES modules for tree shaking
import { debounce, throttle } from 'lodash-es'
Caching Strategies
Implement effective caching for better performance.
Service Worker Caching
// Cache-first strategy for static assets
self.addEventListener('fetch', event => {
if (event.request.url.includes('/static/')) {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(fetchResponse => {
const responseClone = fetchResponse.clone()
caches.open('v1').then(cache => {
cache.put(event.request, responseClone)
})
return fetchResponse
})
})
)
}
})
HTTP Caching Headers
# Static assets
location /static/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# HTML files
location ~* \.html$ {
expires 1h;
add_header Cache-Control "public, must-revalidate";
}
Performance Monitoring
Track performance metrics in production.
Web Vitals Monitoring
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'
function sendToAnalytics(metric) {
// Send to your analytics service
gtag('event', metric.name, {
value: Math.round(metric.value),
metric_id: metric.id,
metric_delta: metric.delta,
})
}
getCLS(sendToAnalytics)
getFID(sendToAnalytics)
getFCP(sendToAnalytics)
getLCP(sendToAnalytics)
getTTFB(sendToAnalytics)
Performance Observer
// Monitor long tasks
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.duration > 50) {
console.warn('Long task detected:', entry)
}
}
})
observer.observe({ type: 'longtask', buffered: true })
Advanced Techniques
Intersection Observer for Lazy Loading
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target
img.src = img.dataset.src
img.classList.remove('lazy')
observer.unobserve(img)
}
})
})
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img)
})
Resource Hints
<!-- Preload critical resources -->
<link rel="preload" href="/critical.css" as="style">
<link rel="preload" href="/hero-font.woff2" as="font" type="font/woff2" crossorigin>
<!-- Prefetch likely next pages -->
<link rel="prefetch" href="/about">
<!-- Preconnect to external domains -->
<link rel="preconnect" href="https://fonts.googleapis.com">
Performance optimization is an ongoing process. Regularly audit your site, monitor real user metrics, and continuously optimize based on data and user feedback.
Enjoyed this article?
Subscribe to our newsletter for more insights on web development, design, and technology.