10 min read
0%

Performance Optimization Tips

Back to Blog
Performance Optimization Tips

Performance Optimization Tips

Web performance isn’t just about speed—it’s about delivering exceptional user experiences. In this comprehensive guide, we’ll explore practical techniques for optimizing your websites from Core Web Vitals to advanced optimization strategies.

Core Web Vitals

Google’s Core Web Vitals measure user-centric performance:

Largest Contentful Paint (LCP)

Target: < 2.5 seconds

LCP measures loading performance. To improve it:

<!-- Preload critical resources -->
<link rel="preload" as="image" href="hero.jpg" />

<!-- Use responsive images -->
<img
  src="hero-small.jpg"
  srcset="hero-small.jpg 400w, hero-medium.jpg 800w, hero-large.jpg 1200w"
  sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
  alt="Hero image"
/>

First Input Delay (FID) / Interaction to Next Paint (INP)

Target: < 100ms (FID), < 200ms (INP)

Optimize JavaScript execution:

// Bad: Blocking main thread
for (let i = 0; i < 1000000; i++) {
  processItem(i);
}

// Good: Break up work
async function processInChunks() {
  for (let i = 0; i < 1000000; i += 1000) {
    await scheduler.yield(); // New API
    for (let j = i; j < Math.min(i + 1000, 1000000); j++) {
      processItem(j);
    }
  }
}

Cumulative Layout Shift (CLS)

Target: < 0.1

Reserve space for dynamic content:

/* Reserve space for images */
.image-container {
  aspect-ratio: 16 / 9;
}

/* Use content-visibility for off-screen content */
.below-fold {
  content-visibility: auto;
  contain-intrinsic-size: 0 500px;
}

Resource Optimization

Image Optimization

Modern image formats offer significant savings:

<picture>
  <source type="image/avif" srcset="image.avif" />
  <source type="image/webp" srcset="image.webp" />
  <img src="image.jpg" alt="Optimized image" loading="lazy" />
</picture>

Font Optimization

Optimize font loading for better performance:

@font-face {
  font-family: "Custom Font";
  src: url("font.woff2") format("woff2");
  font-display: swap; /* Prevent invisible text */
  font-weight: 400;
  unicode-range: U+0000-00FF; /* Latin subset */
}

JavaScript Optimization

Code Splitting

Split your bundles for faster initial loads:

// Dynamic imports
const module = await import("./heavy-module.js");

// Route-based splitting (SvelteKit)
export const load = async () => {
  const { HeavyComponent } =
    await import("$lib/components/HeavyComponent.svelte");
  return { HeavyComponent };
};

Tree Shaking

Ensure your bundler can eliminate dead code:

// Bad: Imports everything
import _ from "lodash";

// Good: Import only what you need
import debounce from "lodash/debounce";

Caching Strategies

HTTP Caching

Implement effective cache headers:

# Static assets
Cache-Control: public, max-age=31536000, immutable

# HTML
Cache-Control: public, max-age=0, must-revalidate

# API responses
Cache-Control: public, max-age=60, stale-while-revalidate=30

Service Workers

Implement offline-first strategies:

self.addEventListener("fetch", (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      if (response) {
        return response; // Serve from cache
      }
      return fetch(event.request).then((response) => {
        // Cache new responses
        return caches.open("v1").then((cache) => {
          cache.put(event.request, response.clone());
          return response;
        });
      });
    }),
  );
});

Network Optimization

HTTP/2 and HTTP/3

Leverage modern protocols:

  • HTTP/2: Multiplexing, server push
  • HTTP/3: QUIC protocol, faster connection establishment

Resource Hints

Help the browser prioritize resources:

<!-- DNS prefetch -->
<link rel="dns-prefetch" href="https://api.example.com" />

<!-- Preconnect -->
<link rel="preconnect" href="https://fonts.googleapis.com" />

<!-- Prefetch -->
<link rel="prefetch" href="/next-page.html" />

<!-- Preload -->
<link rel="preload" href="critical.css" as="style" />

Monitoring and Measurement

Lighthouse

Automate performance audits:

npm install -g lighthouse
lighthouse https://example.com --view

Real User Monitoring (RUM)

Track actual user experiences:

// Web Vitals library
import { getCLS, getFID, getLCP } from "web-vitals";

getCLS(console.log);
getFID(console.log);
getLCP(console.log);

Advanced Techniques

Edge Computing

Move computation closer to users:

// Cloudflare Workers example
export default {
  async fetch(request) {
    const cache = caches.default;
    let response = await cache.match(request);

    if (!response) {
      response = await fetch(request);
      await cache.put(request, response.clone());
    }

    return response;
  },
};

Streaming SSR

Stream HTML as it’s generated:

// SvelteKit streaming
export const load = async () => {
  return {
    streamed: {
      slowData: getSlowData(), // Promise that resolves later
    },
  };
};

Performance Budget

Set and enforce performance budgets:

{
  "budgets": [
    {
      "path": "/*",
      "resourceSizes": [
        { "resourceType": "script", "budget": 170 },
        { "resourceType": "total", "budget": 500 }
      ]
    }
  ]
}

Conclusion

Web performance is an ongoing journey, not a destination. By implementing these techniques and continuously measuring your progress, you can deliver fast, responsive experiences that delight your users.

Remember: Every millisecond counts!


Browser support snapshot

Live support matrix for loading-lazy-attr from Can I Use.

Show static fallback image Data on support for loading-lazy-attr across major browsers from caniuse.com

Source: caniuse.com

Canvas is not supported in your browser