Core Web Vitals, optimization techniques, and performance monitoring
Loading performance - should be under 2.5s
LCP: 1.2s (Good)
Interactivity - should be under 100ms
FID: 45ms (Good)
Visual stability - should be under 0.1
CLS: 0.05 (Good)
Server response time - should be under 600ms
TTFB: 200ms (Good)
First content appears - should be under 1.8s
FCP: 1.1s (Good)
Keep under 1.5MB for mobile
Page size: 1.2MB
Keep under 300KB gzipped
JS: 250KB (gzipped)
Keep under 50KB gzipped
CSS: 35KB (gzipped)
Use WebP, AVIF formats
image.webp (50% smaller)
Minimize to under 50 requests
Requests: 35
Use modern image formats
<img src="image.webp" alt="Description">
Serve appropriate sizes
<img srcset="small.jpg 300w, large.jpg 800w" sizes="(max-width: 600px) 300px, 800px">
Load images on demand
<img loading="lazy" src="image.jpg">
Optimize file sizes
imagemin --quality=85 image.jpg
Use content delivery networks
https://cdn.example.com/images/
Split bundles by routes
const Home = lazy(() => import("./Home"))
Remove unused code
import { useState } from "react" // Only imports useState
Compress JavaScript code
terser --compress --mangle script.js
Load non-critical scripts
<script async src="analytics.js"></script>
Cache resources offline
navigator.serviceWorker.register("/sw.js")
Inline above-the-fold styles
<style>/* Critical styles */</style>
Remove whitespace and comments
cssnano --optimize
Purge unused styles
purgecss --content src/**/*.html
Extract critical styles
styled-components extractCritical
Optimize loading order
Preload critical CSS, defer non-critical
Google's performance audit tool
lighthouse https://example.com
Detailed performance analysis
https://www.webpagetest.org/
Core Web Vitals analysis
https://pagespeed.web.dev/
Built-in performance tools
F12 → Performance tab
Track actual user experience
web-vitals library
Web analytics platform
gtag("event", "web_vitals")
Programmatic access to metrics
web-vitals.getCLS(console.log)
Monitor performance metrics
new PerformanceObserver(callback)
Track resource loading times
performance.getEntriesByType("resource")
Page load timing data
performance.timing.loadEventEnd
Basic performance monitoring implementation
// web-vitals.js
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
function sendToAnalytics(metric) {
// Send to Google Analytics
gtag('event', metric.name, {
value: Math.round(metric.value),
event_category: 'Web Vitals',
event_label: metric.id,
non_interaction: true,
});
}
// Monitor Core Web Vitals
getCLS(sendToAnalytics);
getFID(sendToAnalytics);
getFCP(sendToAnalytics);
getLCP(sendToAnalytics);
getTTFB(sendToAnalytics);
// Custom performance monitoring
const observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
console.log('Performance entry:', entry.name, entry.startTime);
}
});
observer.observe({ entryTypes: ['navigation', 'resource', 'paint'] });
React component for optimized images
// OptimizedImage.jsx
import { useState, useEffect } from 'react';
const OptimizedImage = ({
src,
alt,
width,
height,
sizes = "100vw",
priority = false
}) => {
const [imageSrc, setImageSrc] = useState(src);
const [isLoaded, setIsLoaded] = useState(false);
useEffect(() => {
// Check if WebP is supported
const webpSupported = document.createElement('canvas')
.toDataURL('image/webp')
.indexOf('data:image/webp') === 0;
if (webpSupported && src.includes('.jpg')) {
setImageSrc(src.replace('.jpg', '.webp'));
}
}, [src]);
return (
<div className="image-container">
<img
src={imageSrc}
alt={alt}
width={width}
height={height}
sizes={sizes}
loading={priority ? 'eager' : 'lazy'}
onLoad={() => setIsLoaded(true)}
className={`optimized-image ${isLoaded ? 'loaded' : ''}`}
style={{
opacity: isLoaded ? 1 : 0,
transition: 'opacity 0.3s ease-in-out'
}}
/>
{!isLoaded && (
<div
className="image-placeholder"
style={{ width, height, backgroundColor: '#f0f0f0' }}
/>
)}
</div>
);
};
export default OptimizedImage;
Basic service worker implementation
// sw.js
const CACHE_NAME = 'app-cache-v1';
const urlsToCache = [
'/',
'/styles/main.css',
'/scripts/main.js',
'/images/logo.png'
];
// Install event
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.addAll(urlsToCache))
);
});
// Fetch event - Cache First strategy
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
// Return cached version or fetch from network
return response || fetch(event.request);
})
);
});
// Update cache when new version is available
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
});
// Register service worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js')
.then((registration) => {
console.log('SW registered:', registration);
})
.catch((error) => {
console.log('SW registration failed:', error);
});
});
}
Extract and inline critical CSS
// critical-css.js
import { extractCritical } from 'styled-components';
// Extract critical CSS from styled-components
const criticalCSS = extractCritical(html);
// Inline critical CSS in HTML head
const htmlWithCriticalCSS = `
<!DOCTYPE html>
<html>
<head>
<style id="critical-css">${criticalCSS.css}</style>
<link rel="preload" href="/styles/main.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles/main.css"></noscript>
</head>
<body>
${criticalCSS.html}
</body>
</html>
`;
// Alternative: Use a critical CSS tool
// npm install critical
const critical = require('critical');
critical.generate({
src: 'index.html',
target: {
css: 'critical.css',
html: 'index-critical.html'
},
width: 1300,
height: 900
});
Analyze and optimize JavaScript bundles
// webpack.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all',
},
common: {
name: 'common',
minChunks: 2,
chunks: 'all',
enforce: true
}
}
},
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
})
]
},
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false
})
]
};
// Analyze bundle size
// npm install --save-dev webpack-bundle-analyzer
// npx webpack-bundle-analyzer dist/stats.json
// Tree shaking with ES modules
import { useState, useEffect } from 'react'; // Only imports what's used
// Instead of: import * as React from 'react';
Set up performance budgets in build tools
// .budgetrc
{
"connection": {
"rtt": 50,
"downlink": 10,
"effectiveConnectionType": "4g"
},
"budgets": [
{
"resourceType": "script",
"budget": 300
},
{
"resourceType": "total",
"budget": 1500
},
{
"resourceType": "image",
"budget": 500
}
]
}
// webpack.config.js with performance budgets
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
performance: {
hints: 'warning',
maxEntrypointSize: 300000,
maxAssetSize: 300000,
assetFilter: function(assetFilename) {
return !assetFilename.endsWith('.map');
}
}
};
// Lighthouse CI configuration
// .lighthouserc.js
module.exports = {
ci: {
collect: {
url: ['http://localhost:3000'],
numberOfRuns: 3
},
assert: {
assertions: {
'categories:performance': ['warn', { minScore: 0.9 }],
'first-contentful-paint': ['warn', { maxNumericValue: 2000 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
'first-input-delay': ['error', { maxNumericValue: 100 }]
}
}
}
};
Set up performance budgets and monitor them in CI/CD
Use WebP/AVIF images and implement lazy loading
Implement code splitting and tree shaking
Use service workers for caching and offline functionality
Monitor Core Web Vitals in production