HTML / CSS

How to Improve/Measure Performance in FrontEnd 2023

You get a ticket: "Make the website faster." No specific metric. No target. Just "faster."

15 Oct 2023

How to Improve/Measure Performance in FrontEnd 2023

You get a ticket: "Make the website faster." No specific metric. No target. Just "faster."

I've been in this situation many times. Here's the systematic approach I follow — measure first, then fix the things that actually matter.

1. Enable Compression: GZip or Brotli

This is the lowest-effort, highest-impact optimization. If you're not compressing your assets, you're shipping raw bytes over the wire.

Brotli is the better option. Developed by Google, it provides 15-25% better compression than GZip for text assets. Most modern browsers support it.

If you're using Nginx, enable Brotli with the ngx_brotli module. If you're serving through AWS CloudFront, enable compression in your distribution settings.

Resources:

Benefit: Smaller payloads, faster downloads. Zero code changes required.

Cost: Slightly higher CPU usage on the server for compression. Brotli's highest compression levels are slow — use level 4-6 for dynamic content.

2. Use a CDN

If your assets aren't served from a CDN, users far from your server pay a latency tax on every request.

A CDN caches your static assets (JS, CSS, images, fonts) on edge nodes worldwide. Users download from the nearest node instead of crossing oceans.

Cloudflare and AWS CloudFront are the two I use most. Cloudflare's free tier is generous enough for most projects.

Benefit: Faster asset delivery globally. Built-in caching, compression, and DDoS protection.

Cost: Cache invalidation can be tricky. Stale assets cause bugs that are hard to reproduce.

3. Prefetch Critical Resources

The browser can download resources during idle time — before the user navigates to the next page.

Text
<link rel="prefetch" href="/next-page.js" />
<link rel="preload" href="/critical-font.woff2" as="font" type="font/woff2" crossorigin />

prefetch loads resources for likely future navigation. preload loads resources needed for the current page but discovered late by the browser (like fonts referenced in CSS).

Benefit: Perceived instant navigation. Resources are already cached when the user clicks.

Cost: Wasted bandwidth if the user doesn't navigate to the prefetched page. Be selective — only prefetch routes users are likely to visit.

4. Remove Unused CSS and JavaScript

Even after bundling and minification, you probably ship code that never executes.

Use your bundler's tree-shaking capabilities. Configure Terser for JavaScript minification:

Text
const TerserPlugin = require('terser-webpack-plugin')

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()],
  },
}

For CSS, tools like PurgeCSS analyze your HTML and remove unused selectors. This is especially impactful if you use a utility framework like Tailwind.

Benefit: Smaller bundles. Faster parse and execution time.

Cost: Aggressive purging can remove CSS that's only used dynamically. Test thoroughly.

5. Optimize Images

Images are usually the largest payload on a page. Serve them in modern formats (WebP, AVIF), resize them to the dimensions they're actually displayed at, and lazy-load images below the fold.

Text
<img src="photo.webp" loading="lazy" width="800" height="600" alt="Description" />

Benefit: Dramatic reduction in page weight. A 2MB JPEG can become a 200KB WebP.

Cost: Format support varies. You need fallbacks for older browsers with <picture> elements.

6. Code Split Your Application

Don't ship your entire application in one bundle. Split by route so users only download the code they need for the current page.

In React, use React.lazy() and Suspense. In Next.js, this happens automatically for pages.

Benefit: Faster initial load. Smaller main bundle.

Cost: Additional network requests when navigating. Loading spinners on route transitions.

7. Measure Before and After

None of this matters if you're not measuring. Use:

  • Lighthouse for lab metrics (LCP, FID, CLS)
  • Web Vitals for real-user monitoring
  • Chrome DevTools Performance tab for profiling specific interactions
  • GTMetrix or WebPageTest for waterfall analysis

Set a performance budget. Track it in CI. Performance regressions should fail the build, not get discovered in production.

The Bottom Line

Performance optimization is iterative. Compress your assets. Use a CDN. Lazy-load what you can. Measure the results. Then repeat.

The biggest mistake I see teams make is optimizing without measuring. You'll spend a week refactoring component renders when the real problem is an uncompressed 3MB hero image.