Skip to content
matthewcm.dev

    ↑ ↓ move · ↵ open · tab scopeopen graph →

    Front-end Performance Checklist

    Ship less JS, load images smartly, render only what changed and what's visible, keep layout and paint cheap, and profile before and after.

    Growingtended planted 3 min read
    On this page

    Ship less JS, load images smartly, render only what changed and what’s visible, and keep the browser’s layout and paint work cheap. And profile before and after, because intuition about performance is usually wrong.

    1. The bundle

    • Polyfills buy support for modern JS at a cost on every device. Let the bundler (Vite, say) target only the browsers you actually support.
    • Compression and minification. gzip or brotli cut roughly 70% of the payload; minification strips the rest. Keep source maps (privately) so production bugs stay readable.
    • Code splitting at route or component level (React.lazy + Suspense). “Mega components” are expensive to load and render, and splitting them also separates responsibilities.
    • Tree-shaking through ES module imports, so you only bundle what you use. Big barrel files and TypeScript enums get in the way.
    • Preload and prefetch the next page’s resources when the user hovers or starts navigating.
    • Guard against regressions with Lighthouse CI or performance monitoring in the pipeline, so you can see what each new dependency costs over time.

    2. Images and media

    • Compress, and use modern formats (WebP, AVIF).
    • Lazy-load below the fold (loading="lazy").
    • Responsive loading: pick resolution by viewport and connection with srcset and sizes. An image CDN can generate the variants and cache them at the edge.
    • Video: adaptive bitrate streaming (HLS, DASH).

    3. Components

    • React.memo means “don’t re-render if the props haven’t changed”. Use it on stable, expensive children; skip it where props change every render, because then the comparison is pure overhead.
    • useMemo and useCallback for expensive derived data (filter, sort, paginate) and for stable callbacks into memoised children. React 19’s compiler automates most of this (React 19 Hooks Cheat Sheet).
    • Avoid parent-driven re-renders. Keep state low and use selector stores (Zustand Transient Updates, React State Management Choices).
    • Stable list keys. Never the index for a dynamic list.
    • Virtualisation (windowing) with TanStack Virtual or react-window: render only the rows in the viewport, so huge lists stay at 60fps. TanStack Virtual is headless, so you render its virtual rows yourself. The trade-off is that off-screen content isn’t in the DOM, which affects SEO and find-in-page. Data grids have their own version of this: AG Grid Performance Patterns.
    • Measure with the React Profiler and the DevTools Performance panel. Components that mount and unmount often are the usual suspects (Finding React Re-render and Memory Leaks).

    4. The browser rendering pipeline

    Parse HTML into the DOM and CSS into the CSSOM, combine them into the render tree, then layout (geometry, where layout shifts happen), paint, and composite the layers.

    • Changing geometry (width, top) re-runs layout and paint. Changing transform or opacity only re-composites, so animate those.
    • The virtual DOM batches updates and diffs the new tree against the old one, touching the real DOM only where something changed. With many moving parts and careless state, the diffing itself becomes the cost.
    • Outside React, batch DOM inserts with document.createDocumentFragment() so the page reflows once.

    More on how the browser schedules work in Browser Fundamentals for Front-end Engineers.

    5. CSS

    • Prefer classes to inline style={{}} objects: more readable, and cheaper style recalculation.
    • Don’t over-promote elements to their own compositing layers (will-change, 3D transforms everywhere). Each layer costs memory.

    In short

    • transform and opacity animate without layout or paint.
    • React.memo is wasted when props change on nearly every render.
    • Windowing trades off-screen DOM for a constant render cost.
    • #performance
    • #react
    • #web-vitals
    • #virtualisation
    • #browser-rendering
    • #css

    ↪ Links to (6)