Back to Blog
8 min readPerformance

Web Performance in 2025: Core Web Vitals and Beyond

Master modern web performance optimization with Core Web Vitals, resource loading strategies, and cutting-edge techniques for lightning-fast websites.

Web Performance in 2025: Core Web Vitals and Beyond

Web performance isn't just about fast load times—it's about creating smooth, responsive experiences that keep users engaged. With Core Web Vitals becoming a ranking factor, performance optimization is more important than ever.

Core Web Vitals

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

1. Largest Contentful Paint (LCP)

Measures loading performance. Target: < 2.5 seconds

<span class="hljs-comment">// Measure LCP</span>
<span class="hljs-keyword">new</span> <span class="hljs-title class_">PerformanceObserver</span>(<span class="hljs-function">(<span class="hljs-params">list</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> entries = list.<span class="hljs-title function_">getEntries</span>();
  <span class="hljs-keyword">const</span> lastEntry = entries[entries.<span class="hljs-property">length</span> - <span class="hljs-number">1</span>];

  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;LCP:&#x27;</span>, lastEntry.<span class="hljs-property">renderTime</span> || lastEntry.<span class="hljs-property">loadTime</span>);
}).<span class="hljs-title function_">observe</span>({ <span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;largest-contentful-paint&#x27;</span>, <span class="hljs-attr">buffered</span>: <span class="hljs-literal">true</span> });

Optimization strategies:

<span class="hljs-comment">&lt;!-- Preload critical images --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;preload&quot;</span> <span class="hljs-attr">as</span>=<span class="hljs-string">&quot;image&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/hero.jpg&quot;</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Optimize image formats --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">picture</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">&quot;/hero.avif&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;image/avif&quot;</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">&quot;/hero.webp&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;image/webp&quot;</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/hero.jpg&quot;</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">&quot;Hero&quot;</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">&quot;eager&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">picture</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Inline critical CSS --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">style</span>&gt;</span><span class="language-css">
  <span class="hljs-comment">/* Critical above-the-fold styles */</span>
</span><span class="hljs-tag">&lt;/<span class="hljs-name">style</span>&gt;</span>

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

Measures responsiveness. Target: < 100ms (FID), < 200ms (INP)

<span class="hljs-comment">// Measure FID</span>
<span class="hljs-keyword">new</span> <span class="hljs-title class_">PerformanceObserver</span>(<span class="hljs-function">(<span class="hljs-params">list</span>) =&gt;</span> {
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> entry <span class="hljs-keyword">of</span> list.<span class="hljs-title function_">getEntries</span>()) {
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;FID:&#x27;</span>, entry.<span class="hljs-property">processingStart</span> - entry.<span class="hljs-property">startTime</span>);
  }
}).<span class="hljs-title function_">observe</span>({ <span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;first-input&#x27;</span>, <span class="hljs-attr">buffered</span>: <span class="hljs-literal">true</span> });

Optimization strategies:

<span class="hljs-comment">// Break up long tasks</span>
<span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">processItems</span>(<span class="hljs-params">items</span>) {
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> item <span class="hljs-keyword">of</span> items) {
    <span class="hljs-keyword">await</span> <span class="hljs-title function_">processItem</span>(item);

    <span class="hljs-comment">// Yield to browser</span>
    <span class="hljs-keyword">if</span> (performance.<span class="hljs-title function_">now</span>() % <span class="hljs-number">50</span> &lt; <span class="hljs-number">16</span>) {
      <span class="hljs-keyword">await</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Promise</span>(<span class="hljs-function"><span class="hljs-params">resolve</span> =&gt;</span> <span class="hljs-built_in">setTimeout</span>(resolve, <span class="hljs-number">0</span>));
    }
  }
}

<span class="hljs-comment">// Use requestIdleCallback</span>
<span class="hljs-title function_">requestIdleCallback</span>(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-comment">// Non-critical work</span>
  <span class="hljs-title function_">analyticstracking</span>();
}, { <span class="hljs-attr">timeout</span>: <span class="hljs-number">2000</span> });

<span class="hljs-comment">// Defer non-critical JavaScript</span>
<span class="language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">defer</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/analytics.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span></span>

3. Cumulative Layout Shift (CLS)

Measures visual stability. Target: < 0.1

<span class="hljs-comment">// Measure CLS</span>
<span class="hljs-keyword">let</span> clsScore = <span class="hljs-number">0</span>;

<span class="hljs-keyword">new</span> <span class="hljs-title class_">PerformanceObserver</span>(<span class="hljs-function">(<span class="hljs-params">list</span>) =&gt;</span> {
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> entry <span class="hljs-keyword">of</span> list.<span class="hljs-title function_">getEntries</span>()) {
    <span class="hljs-keyword">if</span> (!entry.<span class="hljs-property">hadRecentInput</span>) {
      clsScore += entry.<span class="hljs-property">value</span>;
    }
  }
  <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;CLS:&#x27;</span>, clsScore);
}).<span class="hljs-title function_">observe</span>({ <span class="hljs-attr">type</span>: <span class="hljs-string">&#x27;layout-shift&#x27;</span>, <span class="hljs-attr">buffered</span>: <span class="hljs-literal">true</span> });

Optimization strategies:

<span class="hljs-comment">/* Reserve space for images */</span>
<span class="hljs-selector-tag">img</span> {
  <span class="hljs-attribute">aspect-ratio</span>: <span class="hljs-number">16</span> / <span class="hljs-number">9</span>;
  <span class="hljs-attribute">width</span>: <span class="hljs-number">100%</span>;
  <span class="hljs-attribute">height</span>: auto;
}

<span class="hljs-comment">/* Reserve space for ads */</span>
<span class="hljs-selector-class">.ad-slot</span> {
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">250px</span>;
}

<span class="hljs-comment">/* Avoid inserting content above existing content */</span>
<span class="hljs-selector-class">.notification</span> {
  <span class="hljs-attribute">position</span>: fixed; <span class="hljs-comment">/* Don&#x27;t shift content */</span>
  <span class="hljs-attribute">top</span>: <span class="hljs-number">0</span>;
}

Resource Loading Strategies

1. Critical Resource Hints

<span class="hljs-comment">&lt;!-- DNS prefetch for external domains --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;dns-prefetch&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://api.example.com&quot;</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Preconnect to establish early connections --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;preconnect&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;https://fonts.googleapis.com&quot;</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Prefetch resources for next page --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;prefetch&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/next-page.html&quot;</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Preload critical resources --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;preload&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/critical.css&quot;</span> <span class="hljs-attr">as</span>=<span class="hljs-string">&quot;style&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;preload&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/font.woff2&quot;</span> <span class="hljs-attr">as</span>=<span class="hljs-string">&quot;font&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;font/woff2&quot;</span> <span class="hljs-attr">crossorigin</span>&gt;</span>

2. JavaScript Loading

<span class="hljs-comment">&lt;!-- Defer non-critical scripts --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">defer</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/app.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Async for independent scripts --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">async</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/analytics.js&quot;</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Module preload --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;modulepreload&quot;</span> <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/app.js&quot;</span>&gt;</span>

3. Dynamic Imports

<span class="hljs-comment">// Lazy load features</span>
button.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">&#x27;click&#x27;</span>, <span class="hljs-title function_">async</span> () =&gt; {
  <span class="hljs-keyword">const</span> { heavyFeature } = <span class="hljs-keyword">await</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">&#x27;./heavy-feature.js&#x27;</span>);
  <span class="hljs-title function_">heavyFeature</span>();
});

<span class="hljs-comment">// Route-based code splitting</span>
<span class="hljs-keyword">const</span> routes = {
  <span class="hljs-string">&#x27;/products&#x27;</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">&#x27;./pages/products.js&#x27;</span>),
  <span class="hljs-string">&#x27;/cart&#x27;</span>: <span class="hljs-function">() =&gt;</span> <span class="hljs-keyword">import</span>(<span class="hljs-string">&#x27;./pages/cart.js&#x27;</span>),
};

Image Optimization

1. Modern Formats

<span class="hljs-tag">&lt;<span class="hljs-name">picture</span>&gt;</span>
  <span class="hljs-comment">&lt;!-- AVIF: Best compression --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">&quot;/image.avif&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;image/avif&quot;</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- WebP: Good compression, wide support --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">&quot;/image.webp&quot;</span> <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;image/webp&quot;</span>&gt;</span>

  <span class="hljs-comment">&lt;!-- JPEG: Fallback --&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/image.jpg&quot;</span> <span class="hljs-attr">alt</span>=<span class="hljs-string">&quot;Description&quot;</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">&quot;lazy&quot;</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">picture</span>&gt;</span>

2. Responsive Images

<span class="hljs-tag">&lt;<span class="hljs-name">img</span>
  <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/image-800.jpg&quot;</span>
  <span class="hljs-attr">srcset</span>=<span class="hljs-string">&quot;
    /image-400.jpg 400w,
    /image-800.jpg 800w,
    /image-1200.jpg 1200w
  &quot;</span>
  <span class="hljs-attr">sizes</span>=<span class="hljs-string">&quot;(max-width: 600px) 400px, 800px&quot;</span>
  <span class="hljs-attr">alt</span>=<span class="hljs-string">&quot;Description&quot;</span>
  <span class="hljs-attr">loading</span>=<span class="hljs-string">&quot;lazy&quot;</span>
  <span class="hljs-attr">decoding</span>=<span class="hljs-string">&quot;async&quot;</span>
&gt;</span>

3. Lazy Loading

<span class="hljs-comment">// Native lazy loading</span>
&lt;img src=<span class="hljs-string">&quot;/image.jpg&quot;</span> loading=<span class="hljs-string">&quot;lazy&quot;</span>&gt;

<span class="hljs-comment">// Intersection Observer for custom loading</span>
<span class="hljs-keyword">const</span> observer = <span class="hljs-keyword">new</span> <span class="hljs-title class_">IntersectionObserver</span>(<span class="hljs-function">(<span class="hljs-params">entries</span>) =&gt;</span> {
  entries.<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">entry</span> =&gt;</span> {
    <span class="hljs-keyword">if</span> (entry.<span class="hljs-property">isIntersecting</span>) {
      <span class="hljs-keyword">const</span> img = entry.<span class="hljs-property">target</span>;
      img.<span class="hljs-property">src</span> = img.<span class="hljs-property">dataset</span>.<span class="hljs-property">src</span>;
      observer.<span class="hljs-title function_">unobserve</span>(img);
    }
  });
});

<span class="hljs-variable language_">document</span>.<span class="hljs-title function_">querySelectorAll</span>(<span class="hljs-string">&#x27;img[data-src]&#x27;</span>).<span class="hljs-title function_">forEach</span>(<span class="hljs-function"><span class="hljs-params">img</span> =&gt;</span> {
  observer.<span class="hljs-title function_">observe</span>(img);
});

4. Image CDNs

<span class="hljs-comment">&lt;!-- Cloudinary --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;https://res.cloudinary.com/demo/image/upload/w_800,f_auto,q_auto/sample.jpg&quot;</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Imgix --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;https://assets.imgix.net/image.jpg?w=800&amp;auto=format,compress&quot;</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Cloudflare Images --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;https://imagedelivery.net/account/image/w=800,f=auto&quot;</span>&gt;</span>

Font Optimization

1. Modern Loading Strategy

<span class="hljs-keyword">@font-face</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">&#x27;Custom Font&#x27;</span>;
  <span class="hljs-attribute">src</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">&#x27;/fonts/font.woff2&#x27;</span>) <span class="hljs-built_in">format</span>(<span class="hljs-string">&#x27;woff2&#x27;</span>);
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">400</span>;
  <span class="hljs-attribute">font-style</span>: normal;
  <span class="hljs-attribute">font-display</span>: swap; <span class="hljs-comment">/* Show fallback immediately */</span>
}

2. Variable Fonts

<span class="hljs-keyword">@font-face</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">&#x27;Inter&#x27;</span>;
  <span class="hljs-attribute">src</span>: <span class="hljs-built_in">url</span>(<span class="hljs-string">&#x27;/fonts/inter-var.woff2&#x27;</span>) <span class="hljs-built_in">format</span>(<span class="hljs-string">&#x27;woff2&#x27;</span>);
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">100</span> <span class="hljs-number">900</span>; <span class="hljs-comment">/* Support all weights */</span>
  <span class="hljs-attribute">font-display</span>: swap;
}

<span class="hljs-selector-tag">h1</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">&#x27;Inter&#x27;</span>, sans-serif;
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">700</span>; <span class="hljs-comment">/* Any weight from 100-900 */</span>
}

3. Subsetting

<span class="hljs-comment"># Create subset with only needed characters</span>
pyftsubset font.ttf \
  --unicodes=<span class="hljs-string">&quot;U+0020-007E&quot;</span> \
  --output-file=<span class="hljs-string">&quot;font-subset.woff2&quot;</span> \
  --flavor=woff2

4. Preload Critical Fonts

<span class="hljs-tag">&lt;<span class="hljs-name">link</span>
  <span class="hljs-attr">rel</span>=<span class="hljs-string">&quot;preload&quot;</span>
  <span class="hljs-attr">href</span>=<span class="hljs-string">&quot;/fonts/font.woff2&quot;</span>
  <span class="hljs-attr">as</span>=<span class="hljs-string">&quot;font&quot;</span>
  <span class="hljs-attr">type</span>=<span class="hljs-string">&quot;font/woff2&quot;</span>
  <span class="hljs-attr">crossorigin</span>
&gt;</span>

Bundle Optimization

1. Code Splitting

<span class="hljs-comment">// webpack.config.js</span>
<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {
  <span class="hljs-attr">optimization</span>: {
    <span class="hljs-attr">splitChunks</span>: {
      <span class="hljs-attr">chunks</span>: <span class="hljs-string">&#x27;all&#x27;</span>,
      <span class="hljs-attr">cacheGroups</span>: {
        <span class="hljs-attr">vendor</span>: {
          <span class="hljs-attr">test</span>: <span class="hljs-regexp">/[\\/]node_modules[\\/]/</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;vendors&#x27;</span>,
        },
        <span class="hljs-attr">common</span>: {
          <span class="hljs-attr">minChunks</span>: <span class="hljs-number">2</span>,
          <span class="hljs-attr">name</span>: <span class="hljs-string">&#x27;common&#x27;</span>,
        },
      },
    },
  },
};

2. Tree Shaking

<span class="hljs-comment">// package.json</span>
{
  <span class="hljs-string">&quot;sideEffects&quot;</span>: <span class="hljs-literal">false</span>
}

<span class="hljs-comment">// Use named imports</span>
<span class="hljs-keyword">import</span> { specific } <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;library&#x27;</span>; <span class="hljs-comment">// ✓ Tree-shakeable</span>
<span class="hljs-keyword">import</span> library <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;library&#x27;</span>; <span class="hljs-comment">// ✗ Imports everything</span>

3. Bundle Analysis

<span class="hljs-comment"># webpack-bundle-analyzer</span>
npm install --save-dev webpack-bundle-analyzer

<span class="hljs-comment"># Add to webpack config</span>
const BundleAnalyzerPlugin = require(<span class="hljs-string">&#x27;webpack-bundle-analyzer&#x27;</span>).BundleAnalyzerPlugin;

plugins: [
  new BundleAnalyzerPlugin()
]

Caching Strategies

1. HTTP Caching

<span class="hljs-comment"># nginx configuration</span>
<span class="hljs-section">location</span> <span class="hljs-regexp">~* \.(js|css|png|jpg|jpeg|gif|svg|ico)$</span> {
  <span class="hljs-attribute">expires</span> <span class="hljs-number">1y</span>;
  <span class="hljs-attribute">add_header</span> Cache-Control <span class="hljs-string">&quot;public, immutable&quot;</span>;
}

<span class="hljs-section">location</span> <span class="hljs-regexp">~* \.(html)$</span> {
  <span class="hljs-attribute">expires</span> <span class="hljs-number">1h</span>;
  <span class="hljs-attribute">add_header</span> Cache-Control <span class="hljs-string">&quot;public, must-revalidate&quot;</span>;
}

2. Cache Busting

<span class="hljs-comment">// Webpack</span>
<span class="hljs-attr">output</span>: {
  <span class="hljs-attr">filename</span>: <span class="hljs-string">&#x27;[name].[contenthash].js&#x27;</span>,
}

<span class="hljs-comment">// Vite</span>
<span class="hljs-attr">build</span>: {
  <span class="hljs-attr">rollupOptions</span>: {
    <span class="hljs-attr">output</span>: {
      <span class="hljs-attr">entryFileNames</span>: <span class="hljs-string">&#x27;[name].[hash].js&#x27;</span>,
    },
  },
}

3. Service Worker Caching

<span class="hljs-comment">// Workbox strategies</span>
<span class="hljs-keyword">import</span> { registerRoute } <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;workbox-routing&#x27;</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">CacheFirst</span>, <span class="hljs-title class_">NetworkFirst</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;workbox-strategies&#x27;</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">CacheableResponsePlugin</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;workbox-cacheable-response&#x27;</span>;
<span class="hljs-keyword">import</span> { <span class="hljs-title class_">ExpirationPlugin</span> } <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;workbox-expiration&#x27;</span>;

<span class="hljs-comment">// Cache images</span>
<span class="hljs-title function_">registerRoute</span>(
  <span class="hljs-function">(<span class="hljs-params">{ request }</span>) =&gt;</span> request.<span class="hljs-property">destination</span> === <span class="hljs-string">&#x27;image&#x27;</span>,
  <span class="hljs-keyword">new</span> <span class="hljs-title class_">CacheFirst</span>({
    <span class="hljs-attr">cacheName</span>: <span class="hljs-string">&#x27;images&#x27;</span>,
    <span class="hljs-attr">plugins</span>: [
      <span class="hljs-keyword">new</span> <span class="hljs-title class_">CacheableResponsePlugin</span>({ <span class="hljs-attr">statuses</span>: [<span class="hljs-number">0</span>, <span class="hljs-number">200</span>] }),
      <span class="hljs-keyword">new</span> <span class="hljs-title class_">ExpirationPlugin</span>({
        <span class="hljs-attr">maxEntries</span>: <span class="hljs-number">60</span>,
        <span class="hljs-attr">maxAgeSeconds</span>: <span class="hljs-number">30</span> * <span class="hljs-number">24</span> * <span class="hljs-number">60</span> * <span class="hljs-number">60</span>,
      }),
    ],
  })
);

Rendering Strategies

1. Static Site Generation (SSG)

<span class="hljs-comment">// Next.js</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">getStaticProps</span>(<span class="hljs-params"></span>) {
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetchData</span>();
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">props</span>: { data } };
}

Best for: Blogs, marketing sites, documentation

2. Incremental Static Regeneration (ISR)

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">getStaticProps</span>(<span class="hljs-params"></span>) {
  <span class="hljs-keyword">return</span> {
    <span class="hljs-attr">props</span>: { data },
    <span class="hljs-attr">revalidate</span>: <span class="hljs-number">60</span>, <span class="hljs-comment">// Rebuild every 60 seconds</span>
  };
}

Best for: E-commerce, news sites with frequent updates

3. Server-Side Rendering (SSR)

<span class="hljs-keyword">export</span> <span class="hljs-keyword">async</span> <span class="hljs-keyword">function</span> <span class="hljs-title function_">getServerSideProps</span>(<span class="hljs-params"></span>) {
  <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> <span class="hljs-title function_">fetchData</span>();
  <span class="hljs-keyword">return</span> { <span class="hljs-attr">props</span>: { data } };
}

Best for: Personalized content, real-time data

4. Client-Side Rendering (CSR)

<span class="hljs-title function_">useEffect</span>(<span class="hljs-function">() =&gt;</span> {
  <span class="hljs-title function_">fetchData</span>().<span class="hljs-title function_">then</span>(setData);
}, []);

Best for: Authenticated pages, dashboards

Performance Monitoring

1. Real User Monitoring (RUM)

<span class="hljs-comment">// web-vitals library</span>
<span class="hljs-keyword">import</span> { getCLS, getFID, getFCP, getLCP, getTTFB } <span class="hljs-keyword">from</span> <span class="hljs-string">&#x27;web-vitals&#x27;</span>;

<span class="hljs-keyword">function</span> <span class="hljs-title function_">sendToAnalytics</span>(<span class="hljs-params">metric</span>) {
  <span class="hljs-title function_">fetch</span>(<span class="hljs-string">&#x27;/analytics&#x27;</span>, {
    <span class="hljs-attr">method</span>: <span class="hljs-string">&#x27;POST&#x27;</span>,
    <span class="hljs-attr">body</span>: <span class="hljs-title class_">JSON</span>.<span class="hljs-title function_">stringify</span>(metric),
  });
}

<span class="hljs-title function_">getCLS</span>(sendToAnalytics);
<span class="hljs-title function_">getFID</span>(sendToAnalytics);
<span class="hljs-title function_">getFCP</span>(sendToAnalytics);
<span class="hljs-title function_">getLCP</span>(sendToAnalytics);
<span class="hljs-title function_">getTTFB</span>(sendToAnalytics);

2. Performance API

<span class="hljs-comment">// Measure custom timings</span>
performance.<span class="hljs-title function_">mark</span>(<span class="hljs-string">&#x27;feature-start&#x27;</span>);
<span class="hljs-comment">// ... feature code ...</span>
performance.<span class="hljs-title function_">mark</span>(<span class="hljs-string">&#x27;feature-end&#x27;</span>);
performance.<span class="hljs-title function_">measure</span>(<span class="hljs-string">&#x27;feature&#x27;</span>, <span class="hljs-string">&#x27;feature-start&#x27;</span>, <span class="hljs-string">&#x27;feature-end&#x27;</span>);

<span class="hljs-keyword">const</span> measure = performance.<span class="hljs-title function_">getEntriesByName</span>(<span class="hljs-string">&#x27;feature&#x27;</span>)[<span class="hljs-number">0</span>];
<span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;Feature took:&#x27;</span>, measure.<span class="hljs-property">duration</span>, <span class="hljs-string">&#x27;ms&#x27;</span>);

3. Network Information API

<span class="hljs-keyword">if</span> (<span class="hljs-string">&#x27;connection&#x27;</span> <span class="hljs-keyword">in</span> navigator) {
  <span class="hljs-keyword">const</span> connection = navigator.<span class="hljs-property">connection</span>;

  <span class="hljs-keyword">if</span> (connection.<span class="hljs-property">effectiveType</span> === <span class="hljs-string">&#x27;4g&#x27;</span>) {
    <span class="hljs-comment">// Load high-quality assets</span>
  } <span class="hljs-keyword">else</span> {
    <span class="hljs-comment">// Load lower-quality assets</span>
  }

  connection.<span class="hljs-title function_">addEventListener</span>(<span class="hljs-string">&#x27;change&#x27;</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-variable language_">console</span>.<span class="hljs-title function_">log</span>(<span class="hljs-string">&#x27;Connection changed:&#x27;</span>, connection.<span class="hljs-property">effectiveType</span>);
  });
}

Advanced Techniques

1. Priority Hints

<span class="hljs-comment">&lt;!-- High priority for critical resources --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/hero.jpg&quot;</span> <span class="hljs-attr">fetchpriority</span>=<span class="hljs-string">&quot;high&quot;</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Low priority for below-the-fold images --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/footer.jpg&quot;</span> <span class="hljs-attr">fetchpriority</span>=<span class="hljs-string">&quot;low&quot;</span>&gt;</span>

<span class="hljs-comment">&lt;!-- Normal priority (default) --&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">&quot;/content.jpg&quot;</span> <span class="hljs-attr">fetchpriority</span>=<span class="hljs-string">&quot;auto&quot;</span>&gt;</span>

2. Compression

<span class="hljs-comment"># nginx gzip</span>
<span class="hljs-attribute">gzip</span> <span class="hljs-literal">on</span>;
<span class="hljs-attribute">gzip_types</span> text/plain text/css application/json application/javascript;
<span class="hljs-attribute">gzip_min_length</span> <span class="hljs-number">1000</span>;

<span class="hljs-comment"># Brotli (better compression)</span>
<span class="hljs-attribute">brotli</span> <span class="hljs-literal">on</span>;
<span class="hljs-attribute">brotli_types</span> text/plain text/css application/json application/javascript;

3. HTTP/2 Server Push

<span class="hljs-comment"># Push critical resources</span>
<span class="hljs-section">location</span> / {
  <span class="hljs-attribute">http2_push</span> /style.css;
  <span class="hljs-attribute">http2_push</span> /script.js;
}

4. Early Hints (103 Status)

<span class="hljs-comment">// Express.js</span>
app.<span class="hljs-title function_">get</span>(<span class="hljs-string">&#x27;/&#x27;</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-comment">// Send early hints</span>
  res.<span class="hljs-title function_">writeEarlyHints</span>({
    <span class="hljs-attr">link</span>: [
      <span class="hljs-string">&#x27;&lt;style.css&gt;; rel=preload; as=style&#x27;</span>,
      <span class="hljs-string">&#x27;&lt;script.js&gt;; rel=preload; as=script&#x27;</span>,
    ],
  });

  <span class="hljs-comment">// Send actual response</span>
  res.<span class="hljs-title function_">send</span>(html);
});

Performance Budget

Set and enforce performance budgets:

<span class="hljs-comment">// webpack.config.js</span>
<span class="hljs-variable language_">module</span>.<span class="hljs-property">exports</span> = {
  <span class="hljs-attr">performance</span>: {
    <span class="hljs-attr">maxEntrypointSize</span>: <span class="hljs-number">250000</span>, <span class="hljs-comment">// 250kb</span>
    <span class="hljs-attr">maxAssetSize</span>: <span class="hljs-number">100000</span>, <span class="hljs-comment">// 100kb</span>
    <span class="hljs-attr">hints</span>: <span class="hljs-string">&#x27;error&#x27;</span>,
  },
};
<span class="hljs-comment">// Lighthouse CI budget</span>
<span class="hljs-punctuation">[</span>
  <span class="hljs-punctuation">{</span>
    <span class="hljs-attr">&quot;resourceSizes&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span> <span class="hljs-attr">&quot;resourceType&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;script&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">&quot;budget&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">125</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
      <span class="hljs-punctuation">{</span> <span class="hljs-attr">&quot;resourceType&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;image&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">&quot;budget&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">200</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
      <span class="hljs-punctuation">{</span> <span class="hljs-attr">&quot;resourceType&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;total&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">&quot;budget&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">500</span> <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span><span class="hljs-punctuation">,</span>
    <span class="hljs-attr">&quot;timings&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-punctuation">[</span>
      <span class="hljs-punctuation">{</span> <span class="hljs-attr">&quot;metric&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;interactive&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">&quot;budget&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">3000</span> <span class="hljs-punctuation">}</span><span class="hljs-punctuation">,</span>
      <span class="hljs-punctuation">{</span> <span class="hljs-attr">&quot;metric&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-string">&quot;first-contentful-paint&quot;</span><span class="hljs-punctuation">,</span> <span class="hljs-attr">&quot;budget&quot;</span><span class="hljs-punctuation">:</span> <span class="hljs-number">1500</span> <span class="hljs-punctuation">}</span>
    <span class="hljs-punctuation">]</span>
  <span class="hljs-punctuation">}</span>
<span class="hljs-punctuation">]</span>

Testing Tools

1. Lighthouse

lighthouse https://example.com --output=html --output-path=./report.html

2. WebPageTest

  • Visit webpagetest.org
  • Test from multiple locations
  • View filmstrip and waterfall

3. Chrome DevTools

  • Performance tab for profiling
  • Coverage tab for unused code
  • Network tab for resource analysis
  • Lighthouse tab for audits

Checklist

Images:

  • Modern formats (AVIF, WebP)
  • Responsive images
  • Lazy loading
  • Proper sizing

JavaScript:

  • Code splitting
  • Defer/async loading
  • Tree shaking
  • Minification

CSS:

  • Critical CSS inline
  • Non-critical CSS deferred
  • Unused CSS removed
  • Minification

Fonts:

  • WOFF2 format
  • font-display: swap
  • Subsetting
  • Preload critical fonts

Caching:

  • Long cache times for static assets
  • Cache busting
  • Service worker caching

Monitoring:

  • Real user monitoring
  • Core Web Vitals tracking
  • Performance budget

Conclusion

Web performance is a continuous journey, not a destination. By focusing on Core Web Vitals, optimizing resources, and monitoring real user experiences, you can build websites that are fast, responsive, and delightful to use.

Start with the basics—optimize images, defer JavaScript, inline critical CSS—then progressively enhance with advanced techniques.

Your users (and search rankings) will thank you.

👨‍💻

Jordan Patel

Web Developer & Technology Enthusiast