Resource Loading Strategies - preload, prefetch, modulepreload

Resource Loading Strategies are techniques for optimizing resource loading in browsers. Proper use of preload, prefetch, and other hints can significantly speed up page loading.

Loading Strategy Spectrum

Preload — Load this immediately!

Purpose: Load critical resources as early as possible.

Preload Syntax

<!-- Critical fonts -->
<link rel="preload" href="/fonts/main.woff2" as="font" type="font/woff2" crossorigin>

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

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

<!-- JavaScript module -->
<link rel="preload" href="/app.js" as="script">

When to Use Preload

Good:

<!-- Fonts used in critical CSS -->
<link rel="preload" href="/fonts/heading.woff2" as="font" crossorigin>

<!-- LCP image (Largest Contentful Paint) -->
<link rel="preload" href="/hero-image.jpg" as="image">

<!-- Critical CSS (above the fold) -->
<link rel="preload" href="/above-fold.css" as="style">

Bad:

<!-- Don't preload everything! -->
<link rel="preload" href="/image1.jpg" as="image">
<link rel="preload" href="/image2.jpg" as="image">
<link rel="preload" href="/image3.jpg" as="image">
<!-- This slows down loading! -->

Resource Types (as attribute)

TypeExample
scriptJavaScript files
styleCSS files
fontFonts (requires crossorigin)
imageImages
fetchAPI requests, JSON
videoVideo files
audioAudio files

Prefetch — Load when idle

Purpose: Load resources for next navigation (low priority).

Prefetch Syntax

<!-- Page user will likely navigate to -->
<link rel="prefetch" href="/next-page.html">

<!-- JavaScript for next page -->
<link rel="prefetch" href="/next-page.js">

<!-- Images that will appear on scroll -->
<link rel="prefetch" href="/below-fold-image.jpg">

When to Use Prefetch

Good:

<!-- On product page - prefetch cart -->
<link rel="prefetch" href="/cart.js">

<!-- On landing page - prefetch signup page -->
<link rel="prefetch" href="/signup">

<!-- In carousel - prefetch next image -->
<link rel="prefetch" href="/carousel-image-2.jpg">

Bad:

<!-- Don't prefetch critical resources for current page! -->
<link rel="prefetch" href="/hero-image.jpg"> <!-- Should be preload! -->

Modulepreload — Preload for ES modules

Purpose: Preload for JavaScript modules + their dependencies.

Modulepreload Syntax

<!-- Load module and its dependencies -->
<link rel="modulepreload" href="/app.js">

<!-- This will also load imports inside app.js: -->
<!-- import { utils } from './utils.js' -->
<!-- import { api } from './api.js' -->

Modulepreload Benefits

// app.js
import { helper } from './helper.js';
import { api } from './api.js';

// Without modulepreload:
// 1. Load app.js
// 2. Parse app.js
// 3. Discover imports
// 4. Load helper.js and api.js  Delay!

// With modulepreload:
// 1. Load app.js, helper.js, api.js in parallel
// 2. Parse and execute

DNS-Prefetch — Resolve DNS early

Purpose: Perform DNS lookup for external domain.

DNS-Prefetch Syntax

<!-- External resources -->
<link rel="dns-prefetch" href="https://fonts.googleapis.com">
<link rel="dns-prefetch" href="https://cdn.example.com">
<link rel="dns-prefetch" href="https://analytics.google.com">

Time Savings

Without dns-prefetch:
User action → DNS lookup (20-120ms) → Connect → Request

With dns-prefetch:
DNS already ready! → Connect → Request
Savings: 20-120ms

Preconnect — Establish connection early

Purpose: DNS + TCP + TLS handshake for external domain.

Preconnect Syntax

<!-- Critical external resources -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://cdn.example.com">

What preconnect includes

1. DNS lookup     (20-120ms)
2. TCP handshake  (RTT)
3. TLS handshake  (RTT)
----------------------------
Total savings: 100-500ms!

Preconnect vs DNS-Prefetch

dns-prefetchpreconnect
DNS lookupYesYes
TCP handshakeNoYes
TLS handshakeNoYes
CostCheapMore expensive
WhenMany domainsCritical domains (2-3)

Priority Hints

Attribute fetchpriority controls loading priority:

<!-- High priority for LCP image -->
<img src="/hero.jpg" fetchpriority="high">

<!-- Low priority for below-fold image -->
<img src="/footer-logo.jpg" fetchpriority="low" loading="lazy">

<!-- Critical CSS -->
<link rel="stylesheet" href="/critical.css" fetchpriority="high">

<!-- Non-critical JavaScript -->
<script src="/analytics.js" fetchpriority="low" async></script>

Browser Priorities (default)

ResourcePriority
HTMLHighest
CSS (in <head>)Highest
FontsHigh
Scripts (in <head>)High
Images (in viewport)High
Scripts (async)Low
Images (below fold)Low

Critical Request Chains

Critical request chain — sequence of blocking resources:

<!-- Bad: deep chain -->
<html>
<head>
  <link rel="stylesheet" href="/style.css">
  <!-- In style.css: -->
  <!-- @import url('/fonts.css'); -->
  <!-- In fonts.css: -->
  <!-- @font-face { src: url('/font.woff2'); } -->
</head>

Depth = 3:

  1. Load style.css
  2. Parse → find fonts.css → load
  3. Parse → find font.woff2 → load

Solution:

<!-- Good: parallel loading -->
<head>
  <link rel="preload" href="/font.woff2" as="font" crossorigin>
  <link rel="stylesheet" href="/style.css">
</head>
<!-- Depth = 1, everything parallel! -->

Practical Examples

E-commerce Site

<head>
  <!-- Critical for LCP -->
  <link rel="preload" href="/hero-product.jpg" as="image" fetchpriority="high">
  <link rel="preload" href="/fonts/main.woff2" as="font" crossorigin>
  
  <!-- Critical external resources -->
  <link rel="preconnect" href="https://cdn.shopify.com">
  
  <!-- Non-critical external -->
  <link rel="dns-prefetch" href="https://analytics.google.com">
  
  <!-- Prefetch for likely navigation -->
  <link rel="prefetch" href="/cart">
  <link rel="prefetch" href="/checkout.js">
</head>

SPA (Single Page Application)

<!-- Preload critical chunks -->
<link rel="modulepreload" href="/app.js">
<link rel="modulepreload" href="/router.js">

<!-- Prefetch route chunks -->
<link rel="prefetch" href="/routes/home.js">
<link rel="prefetch" href="/routes/about.js">

Best Practices

1

Preload only critical resources

Maximum 3-5 preloads. More = bandwidth competition.

2

Prefetch for predictable navigation

Analyze user journey and prefetch likely transitions.

3

Preconnect to critical CDNs

No more than 2-3 preconnects (expensive operation).

4

Use fetchpriority

Help browser prioritize LCP resources.

5

Measure impact

Use Lighthouse, WebPageTest for validation.

Analysis Tools

Chrome DevTools

Network tab → Priority column
High = Critical Path
Low = Prefetch candidates

Lighthouse

- "Preload key requests"
- "Reduce initial server response time"
- "Eliminate render-blocking resources"

Summary:

Proper use of resource hints (preload, prefetch, preconnect) can reduce load time by 20-50%. Key is understanding Critical Path and user journey. Preload for critical resources, prefetch for likely transitions, preconnect for external APIs/CDNs.