Frontend Performance Optimization
Performance directly impacts user engagement and conversion rates. This section covers techniques for optimizing frontend applications.
Core Web Vitals
| Metric | Target | Description |
|---|---|---|
| LCP (Largest Contentful Paint) | < 2.5s | Time until largest content element is visible |
| FID (First Input Delay) | < 100ms | Time from first interaction to browser response |
| CLS (Cumulative Layout Shift) | < 0.1 | Measure of visual stability during page load |
Loading Performance
Code Splitting
Code splitting divides the application bundle into smaller chunks loaded on demand.
Route-based splitting: Use lazy loading with dynamic imports to load each route's components only when navigating to that route. For example, the Home and Profile components load only when the user visits those routes.
Component-based splitting: Load heavy components on demand rather than including them in the initial bundle.
Resource Prioritization
Resource hints: Use link elements with rel="preload" to load critical resources (CSS, fonts, hero images) needed for the current page. Use rel="prefetch" to load resources needed for likely future navigation.
| Hint | Purpose | Use Case |
|---|---|---|
| preload | Load resource for current page | Critical CSS, fonts, hero images |
| prefetch | Load resource for future navigation | Next page assets |
| preconnect | Establish early connection | Third-party domains |
Image Optimization
| Technique | Description |
|---|---|
| Lazy loading | Load images when they enter viewport |
| Responsive images (srcset) | Serve appropriate size for device |
| Modern formats (WebP, AVIF) | Smaller file sizes than JPEG/PNG |
| Proper sizing | Match image dimensions to display size |
Rendering Performance
Virtual Scrolling
Virtual scrolling renders only visible items in a list, reducing DOM nodes.
Implementation approach:
- Calculate which items are visible based on scroll position and container height
- Render only those items to the DOM
- Use CSS transforms to position items correctly within the scrollable container
- Update visible items as the user scrolls
The container maintains the full height as if all items were rendered, but only the visible items exist in the DOM. This dramatically reduces memory usage and improves performance for lists with thousands of items.
Debouncing and Throttling
| Technique | Behavior | Implementation |
|---|---|---|
| Debounce | Execute after delay with no new calls | Delay resets on each call |
| Throttle | Execute at most once per interval | Fixed execution rate |
Debounce implementation: Store a timeout ID. On each call, clear the existing timeout and set a new one. The function executes only when no new calls occur for the specified delay.
Throttle implementation: Track the last execution time. On each call, check if enough time has elapsed since the last execution. If so, execute the function and update the last execution time.
Memoization
Memoization caches computed results to avoid redundant calculations.
React.memo: Wraps a component to prevent re-rendering when props have not changed. The component only re-renders when its props differ from the previous render.
useMemo: Caches a computed value and only recalculates when dependencies change. Useful for expensive calculations that should not run on every render.
useCallback: Caches a function reference and only creates a new function when dependencies change. Prevents child components from re-rendering due to new function references.
Caching
Browser Caching
| Cache-Control Directive | Behavior |
|---|---|
public, max-age=31536000 | Cache for 1 year, suitable for static assets |
no-cache | Revalidate with server before using cached version |
no-store | Do not cache response |
Usage: Apply long cache durations (such as one year) to static assets that include content hashes in their filenames. Use no-cache for dynamic content that should be revalidated on each request.
Service Workers
Service workers intercept network requests and serve cached responses.
Cache-first strategy: The service worker listens for fetch events. For each request, it first checks the cache for a matching response. If found, it returns the cached response. If not found, it fetches from the network.
| Strategy | Behavior | Use Case |
|---|---|---|
| Cache first | Serve from cache, fall back to network | Static assets |
| Network first | Fetch from network, fall back to cache | Dynamic content |
| Stale while revalidate | Serve cache, update in background | Frequently updated content |
Performance Measurement
| Tool | Purpose |
|---|---|
| Lighthouse | Audit performance, accessibility, SEO |
| Chrome DevTools Performance panel | Analyze runtime performance |
| Web Vitals library | Measure Core Web Vitals in production |
| webpack-bundle-analyzer | Visualize bundle composition |
Performance Checklist
| Area | Optimization |
|---|---|
| Loading | Code splitting, lazy loading, resource hints |
| Rendering | Virtualization, debouncing, memoization |
| Images | Lazy loading, responsive images, modern formats |
| Caching | Browser cache headers, service workers |
| Bundle | Tree shaking, compression, dependency analysis |