Advanced image optimization goes beyond basic responsive images and lazy loading. This guide covers CDN integration, build-time optimization, performance monitoring, and automated optimization pipelines that ensure your images perform optimally at scale in production environments.
CDN Integration and Optimization
CDN Configuration Helper
// utils/cdn.ts
interface CDNConfig {
baseUrl: string;
transformations: {
format?: 'auto' | 'webp' | 'avif';
quality?: number;
width?: number;
height?: number;
fit?: 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
dpr?: number;
};
}
export class CDNImageOptimizer {
constructor(private config: CDNConfig) {}
generateUrl(path: string, options: Partial<CDNConfig['transformations']> = {}): string {
const transformations = { ...this.config.transformations, ...options };
// Cloudinary format
if (this.config.baseUrl.includes('cloudinary')) {
return this.cloudinaryUrl(path, transformations);
}
// Imgix format
if (this.config.baseUrl.includes('imgix')) {
return this.imgixUrl(path, transformations);
}
// Cloudflare Images format
if (this.config.baseUrl.includes('cloudflare')) {
return this.cloudflareUrl(path, transformations);
}
// Generic CDN with query params
return this.genericUrl(path, transformations);
}
private cloudinaryUrl(path: string, transforms: any): string {
const transformString = Object.entries(transforms)
.map(([key, value]) => {
switch (key) {
case 'width':
return `w_${value}`;
case 'height':
return `h_${value}`;
case 'quality':
return `q_${value}`;
case 'format':
return value === 'auto' ? 'f_auto' : `f_${value}`;
case 'dpr':
return `dpr_${value}`;
case 'fit':
return `c_${value}`;
default:
return '';
}
})
.filter(Boolean)
.join(',');
return `${this.config.baseUrl}/${transformString}/${path}`;
}
private imgixUrl(path: string, transforms: any): string {
const params = new URLSearchParams();
Object.entries(transforms).forEach(([key, value]) => {
switch (key) {
case 'width':
params.set('w', value.toString());
break;
case 'height':
params.set('h', value.toString());
break;
case 'quality':
params.set('q', value.toString());
break;
case 'format':
if (value === 'auto') {
params.set('auto', 'format');
} else {
params.set('fm', value.toString());
}
break;
case 'dpr':
params.set('dpr', value.toString());
break;
case 'fit':
params.set('fit', value.toString());
break;
}
});
return `${this.config.baseUrl}/${path}?${params.toString()}`;
}
private cloudflareUrl(path: string, transforms: any): string {
const options = Object.entries(transforms)
.map(([key, value]) => {
switch (key) {
case 'width':
return `width=${value}`;
case 'height':
return `height=${value}`;
case 'quality':
return `quality=${value}`;
case 'format':
return `format=${value}`;
case 'fit':
return `fit=${value}`;
default:
return '';
}
})
.filter(Boolean)
.join(',');
return `${this.config.baseUrl}/cdn-cgi/image/${options}/${path}`;
}
private genericUrl(path: string, transforms: any): string {
const params = new URLSearchParams();
Object.entries(transforms).forEach(([key, value]) => {
params.set(key, value.toString());
});
return `${this.config.baseUrl}/${path}?${params.toString()}`;
}
}
// React hook for CDN images
function useCDNImage() {
const optimizer = useMemo(() => {
return new CDNImageOptimizer({
baseUrl: process.env.NEXT_PUBLIC_CDN_URL || '',
transformations: {
format: 'auto',
quality: 80,
},
});
}, []);
const generateSrcSet = useCallback(
(path: string, widths: number[]) => {
return widths
.map((width) => {
const url = optimizer.generateUrl(path, { width });
return `${url} ${width}w`;
})
.join(', ');
},
[optimizer],
);
const generateUrl = useCallback(
(path: string, options?: any) => {
return optimizer.generateUrl(path, options);
},
[optimizer],
);
return { generateUrl, generateSrcSet };
}Smart CDN Caching Strategy
// CDN cache optimization
interface CacheStrategy {
images: {
maxAge: number;
staleWhileRevalidate: number;
immutable?: boolean;
};
transforms: {
maxAge: number;
staleWhileRevalidate: number;
};
}
const cacheStrategy: CacheStrategy = {
images: {
maxAge: 31536000, // 1 year for original images
staleWhileRevalidate: 86400, // 1 day
immutable: true,
},
transforms: {
maxAge: 2592000, // 30 days for transformed images
staleWhileRevalidate: 86400, // 1 day
},
};
// Cloudflare Worker for image optimization
export default {
async fetch(request: Request): Promise<Response> {
const url = new URL(request.url);
const { pathname, searchParams } = url;
// Extract image path and transformation params
const imagePath = pathname.replace('/images/', '');
const width = searchParams.get('w');
const quality = searchParams.get('q') || '80';
const format = searchParams.get('f') || 'auto';
// Check cache first
const cacheKey = `image:${imagePath}:${width}:${quality}:${format}`;
const cached = await caches.default.match(cacheKey);
if (cached) {
return cached;
}
// Fetch and transform image
const transformedImage = await transformImage(imagePath, {
width: width ? parseInt(width) : undefined,
quality: parseInt(quality),
format,
});
// Cache response
const response = new Response(transformedImage, {
headers: {
'Content-Type': `image/${format}`,
'Cache-Control': `public, max-age=${cacheStrategy.transforms.maxAge}, stale-while-revalidate=${cacheStrategy.transforms.staleWhileRevalidate}`,
'CDN-Cache-Control': `max-age=${cacheStrategy.transforms.maxAge}`,
},
});
// Store in cache
await caches.default.put(cacheKey, response.clone());
return response;
},
};Image Loading Performance Patterns
Priority Loading Strategy
// Priority-based image loading
interface ImagePriority {
path: string;
priority: 'high' | 'medium' | 'low';
viewport: 'above-fold' | 'below-fold';
critical?: boolean;
}
class ImageLoadingManager {
private loadingQueue: Map<string, ImagePriority> = new Map();
private loadedImages: Set<string> = new Set();
private maxConcurrent = 3;
private currentLoading = 0;
addToQueue(image: ImagePriority): void {
this.loadingQueue.set(image.path, image);
this.processQueue();
}
private async processQueue(): Promise<void> {
if (this.currentLoading >= this.maxConcurrent) return;
// Sort by priority
const sorted = Array.from(this.loadingQueue.entries()).sort(([, a], [, b]) => {
const priorityWeight = { high: 3, medium: 2, low: 1 };
const viewportWeight = { 'above-fold': 2, 'below-fold': 1 };
const criticalWeight = a.critical ? 10 : 0;
const scoreA = priorityWeight[a.priority] + viewportWeight[a.viewport] + criticalWeight;
const scoreB =
priorityWeight[b.priority] + viewportWeight[b.viewport] + (b.critical ? 10 : 0);
return scoreB - scoreA;
});
const [path, priority] = sorted[0] || [];
if (!path || this.loadedImages.has(path)) return;
this.loadingQueue.delete(path);
this.currentLoading++;
try {
await this.loadImage(path, priority);
this.loadedImages.add(path);
} finally {
this.currentLoading--;
if (this.loadingQueue.size > 0) {
this.processQueue();
}
}
}
private loadImage(path: string, priority: ImagePriority): Promise<void> {
return new Promise((resolve, reject) => {
const img = new Image();
// Set priority attributes
if (priority.critical) {
img.decoding = 'sync';
img.fetchPriority = 'high';
} else {
img.decoding = 'async';
img.fetchPriority = priority.priority;
}
img.onload = () => resolve();
img.onerror = reject;
img.src = path;
});
}
}
// React hook for priority loading
function usePriorityImageLoading() {
const manager = useMemo(() => new ImageLoadingManager(), []);
const loadImage = useCallback(
(path: string, options: Omit<ImagePriority, 'path'>) => {
manager.addToQueue({ path, ...options });
},
[manager],
);
return { loadImage };
}Adaptive Loading Based on Network
// Network-aware image loading
function useNetworkAwareImages() {
const [connectionType, setConnectionType] = useState<string>('4g');
const [effectiveType, setEffectiveType] = useState<string>('4g');
useEffect(() => {
if ('connection' in navigator) {
const connection = (navigator as any).connection;
setConnectionType(connection.type || '4g');
setEffectiveType(connection.effectiveType || '4g');
const updateConnection = () => {
setConnectionType(connection.type || '4g');
setEffectiveType(connection.effectiveType || '4g');
};
connection.addEventListener('change', updateConnection);
return () => connection.removeEventListener('change', updateConnection);
}
}, []);
const getImageQuality = useCallback(() => {
if (effectiveType === 'slow-2g' || effectiveType === '2g') {
return 40; // Low quality for slow connections
}
if (effectiveType === '3g') {
return 60; // Medium quality
}
return 80; // High quality for 4g+
}, [effectiveType]);
const getImageFormat = useCallback(() => {
if (effectiveType === 'slow-2g' || effectiveType === '2g') {
return 'webp'; // Smaller file size
}
return 'auto'; // Let CDN decide
}, [effectiveType]);
const shouldLoadImage = useCallback(
(priority: 'high' | 'medium' | 'low') => {
if (effectiveType === 'slow-2g') {
return priority === 'high';
}
if (effectiveType === '2g') {
return priority !== 'low';
}
return true; // Load all images on faster connections
},
[effectiveType],
);
return {
connectionType,
effectiveType,
getImageQuality,
getImageFormat,
shouldLoadImage,
};
}Build-Time Image Optimization
Webpack Image Optimization
// webpack.config.js
const ImageMinimizerPlugin = require('imagemin-webpack-plugin').default;
const imageminWebp = require('imagemin-webp');
const imageminAvif = require('imagemin-avif');
module.exports = {
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'images/',
name: '[name].[contenthash].[ext]',
},
},
{
loader: 'image-webpack-loader',
options: {
mozjpeg: {
progressive: true,
quality: 80,
},
optipng: {
enabled: false,
},
pngquant: {
quality: [0.65, 0.9],
speed: 4,
},
gifsicle: {
interlaced: false,
},
webp: {
quality: 80,
},
},
},
],
},
],
},
plugins: [
new ImageMinimizerPlugin({
test: /\.(jpe?g|png|gif|svg)$/i,
minimizerOptions: {
plugins: [
// Generate WebP versions
['imagemin-webp', { quality: 80 }],
// Generate AVIF versions
['imagemin-avif', { quality: 80 }],
],
},
}),
],
};Next.js Image Component Configuration
// next.config.js
module.exports = {
images: {
domains: ['example.com', 'cdn.example.com'],
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 768, 1024, 1280, 1600],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
minimumCacheTTL: 31536000, // 1 year
dangerouslyAllowSVG: false,
},
// Custom image loader
loader: 'custom',
loaderFile: './lib/imageLoader.js',
};
// lib/imageLoader.js
export default function customLoader({ src, width, quality }) {
const params = new URLSearchParams();
params.set('w', width.toString());
if (quality) params.set('q', quality.toString());
return `https://cdn.example.com/images/${src}?${params.toString()}`;
}
// Optimized Image component
import Image from 'next/image';
interface OptimizedImageProps {
src: string;
alt: string;
priority?: boolean;
className?: string;
sizes?: string;
}
export function OptimizedImage({
src,
alt,
priority = false,
className,
sizes = '(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw',
}: OptimizedImageProps) {
return (
<Image
src={src}
alt={alt}
fill
priority={priority}
className={className}
sizes={sizes}
quality={80}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAv/xAAhEAACAQMDBQAAAAAAAAAAAAABAgMABAUGIWGRkqGx0f/EABUBAQEAAAAAAAAAAAAAAAAAAAMF/8QAGhEAAgIDAAAAAAAAAAAAAAAAAAECEgMRkf/aAAwDAQACEQMRAD8AltJagyeH0AthI5xdrLcNM91BF5pX2HaH9bcfaSXWGaRmknyJckliyjqTzSlT54b6bk+h0R+JNnI5Ny+3V6ArkHqiOmQPd4aZJ2JB6HZ8qNHqidHTbGDKLGbewlVN0BxvM3nLzrflPIxdoFhYFgtWSDMIJOwAP7tBQXExN3SLBpFhLzJ2TL6BwuZKAACQoM9VlkjSPXLH4KYo5J8W8oo0OTKmVzRqIAyTnOFAhV0pMDj8Xb8aMsL43/tB/9k="
/>
);
}Performance Monitoring and Metrics
// Image performance monitoring
interface ImageMetrics {
src: string;
loadTime: number;
fileSize: number;
renderTime: number;
format: string;
dimensions: { width: number; height: number };
cacheHit: boolean;
}
class ImagePerformanceMonitor {
private metrics: Map<string, ImageMetrics> = new Map();
private observer: PerformanceObserver;
constructor() {
this.setupPerformanceObserver();
this.setupIntersectionObserver();
}
private setupPerformanceObserver(): void {
this.observer = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
if (entry.entryType === 'resource' && entry.initiatorType === 'img') {
this.recordImageLoad(entry as PerformanceResourceTiming);
}
}
});
this.observer.observe({ entryTypes: ['resource'] });
}
private recordImageLoad(entry: PerformanceResourceTiming): void {
const metrics: ImageMetrics = {
src: entry.name,
loadTime: entry.duration,
fileSize: entry.transferSize,
renderTime: entry.responseEnd - entry.startTime,
format: this.extractFormat(entry.name),
dimensions: { width: 0, height: 0 }, // Will be updated when image loads
cacheHit: entry.transferSize === 0,
};
this.metrics.set(entry.name, metrics);
this.reportMetrics(metrics);
}
private extractFormat(url: string): string {
const match = url.match(/\.(\w+)(\?|$)/);
return match ? match[1] : 'unknown';
}
private reportMetrics(metrics: ImageMetrics): void {
// Report to analytics
if (typeof gtag !== 'undefined') {
gtag('event', 'image_load', {
event_category: 'performance',
event_label: metrics.format,
value: Math.round(metrics.loadTime),
custom_map: {
file_size: metrics.fileSize,
cache_hit: metrics.cacheHit,
},
});
}
// Report to custom analytics
fetch('/api/analytics/image-performance', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(metrics),
}).catch(() => {
// Silently fail
});
}
getMetrics(): ImageMetrics[] {
return Array.from(this.metrics.values());
}
getAverageLoadTime(): number {
const metrics = this.getMetrics();
return metrics.reduce((sum, m) => sum + m.loadTime, 0) / metrics.length;
}
getCacheHitRate(): number {
const metrics = this.getMetrics();
const cacheHits = metrics.filter((m) => m.cacheHit).length;
return cacheHits / metrics.length;
}
private setupIntersectionObserver(): void {
// Monitor when images become visible
const imageObserver = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting && entry.target.tagName === 'IMG') {
const img = entry.target as HTMLImageElement;
const metrics = this.metrics.get(img.src);
if (metrics) {
metrics.dimensions = {
width: img.naturalWidth,
height: img.naturalHeight,
};
}
}
});
});
// Observe all images
document.querySelectorAll('img').forEach((img) => {
imageObserver.observe(img);
});
}
}
// React hook for image performance monitoring
function useImagePerformanceMonitoring() {
const [monitor] = useState(() => new ImagePerformanceMonitor());
const getPerformanceReport = useCallback(() => {
return {
totalImages: monitor.getMetrics().length,
averageLoadTime: monitor.getAverageLoadTime(),
cacheHitRate: monitor.getCacheHitRate(),
metrics: monitor.getMetrics(),
};
}, [monitor]);
return { getPerformanceReport };
}