Resource Hints: preload, prefetch, modulepreload, dns-prefetch
- Last updated
- Prerequisites:
- Critical rendering path basics
- Understanding of HTML parsing and network requests
- browser
- preload
- prefetch
- modulepreload
- resource-hints
- performance
Read at your depth
The practical view
Resource hints tell the browser about future needs: <link rel="preload" href="font.woff2" as="font"> fetches a critical resource early (before the parser discovers it). <link rel="prefetch" href="/next-page.js"> fetches a likely-next resource at low priority during idle. <link rel="modulepreload" href="module.js"> fetches + prepares an ES module. <link rel="dns-prefetch" href="//api.example.com"> resolves the DNS early. <link rel="preconnect" href="//cdn.example.com"> opens the connection early. Use preload for above-the-fold critical resources, prefetch for probable future navigations, and preconnect/dns-prefetch for third-party origins.
The same idea in other frameworks
Vite/webpack emit preload/modulepreload for code-split chunks; React Router prefetch integrations use prefetch hints.Angular SSR emits preload for critical CSS/fonts; lazy chunks get modulepreload.Nuxt emits prefetch/preload for route chunks and fonts automatically.SvelteKit emits preload hints for critical assets and prefetch for link hover via its own hinting.Legacy vs modern
Font discovered late by CSS vs preloaded font
A font referenced only in CSS is discovered after CSSOM parsing — delaying text render; preloading it starts the fetch during HTML parsing.
@font-face { src: url('/fonts/body.woff2'); } /* ❌ OLD: font found only when CSS is parsed */<link rel="preload" href="/fonts/body.woff2" as="font" type="font/woff2" crossorigin /> <!-- ✅ NEW -->Interview gotchas
Context
This tests the resource-hint semantics — interviewers want the priority/execution distinction and the cache behavior, since mixing them up causes real performance mistakes.
The mechanical answer
preload is for resources the CURRENT page needs but that the parser would discover too late (critical fonts, hero images, early scripts). It is a high-priority fetch initiated during parsing, and the response is used by the current page. prefetch is for resources a FUTURE page will likely need (next route's JS/CSS/images). It is a low-priority, idle-time fetch stored in the HTTP cache — the prefetched response is NOT executed or rendered, just cached, so a later navigation can reuse it. Key distinctions: preload has high priority and is consumed now; prefetch has low priority and is cached for later. Prefetching too aggressively wastes bandwidth/data, and prefetch does not guarantee the future page will use the exact URL.
Trap
The naive answer is 'prefetch is just a lower-priority preload'. They serve different pages (current vs future) and have different cache/execution semantics. Another trap: forgetting crossorigin on font preloads — fonts are fetched with CORS mode, so a preload without crossorigin and the actual font request with it are treated as two different requests, wasting the preload. Candidates who explain the current-vs-future distinction and the crossorigin gotcha show real understanding.
Context
This probes the ES module preparation pipeline — interviewers want to know that modulepreload fetches AND parses/compiles, which is more than preload, and why it matters for dynamic import latency.
The mechanical answer
A plain preload with as=script only fetches the file. modulepreload additionally fetches, parses, and (optionally) compiles the module, so that when a dynamic import() or static import later references it, the module is already parsed and compiled — avoiding the parse/compile latency on the critical path. Bundlers (Vite/webpack/Rollup) emit modulepreload links for code-split chunks precisely because navigation or interaction will import them soon; the hint hides the module preparation cost. It also pre-emptively populates the module map. The cost is that parse/compile is real work done even if the module is never used, so modulepreload should target chunks that are likely to be imported.
Trap
The naive answer is 'modulepreload is preload for ES modules'. It is preload PLUS parse/compile — more work, more memory. Another trap: thinking modulepreload guarantees the module executes — it does not; it prepares it for a later import. Candidates who mention the module map and the parse/compile step show real understanding.