preload
The preload plugin watches registered link elements via IntersectionObserver
and proactively loads pages before the user clicks.
It respects network conditions and supports three strategies.
Usage
preload is included in @erikt/ajax — no separate package needed:
import ajax, { preload } from "@erikt/ajax"
ajax.use(preload({
strategy: ["prefetch", "prerender"],
ignore: ["/cart", "/profile"],
}))
Options
| Option | Type | Default | Description |
|---|---|---|---|
strategy |
PreloadStrategy | PreloadStrategy[] |
'prefetch' |
How to load the URL |
threshold |
number |
0 |
IntersectionObserver threshold |
respectConnection |
boolean |
true |
Skip on saveData or 2G |
ignore |
IgnoreRule | IgnoreRule[] |
[] |
URLs to never preload |
Strategies
prefetch — Injects <link rel="prefetch">.
Caches the response in the HTTP cache so navigation skips the network wait.
prerender — Uses the Speculation Rules API
to fully render the page in a hidden tab. Navigation is instant.
Falls back to prefetch when unsupported.
fetch — Fires a low-priority fetch().
Useful for warming server-side caches without storing a browser-side response.
Ignoring routes
Pass a string (matched against pathname), RegExp, or a function:
preload({
ignore: [
"/cart", // exact pathname
/^\/user/, // regex
url => url.includes("token="), // function
]
})
Invalidating the cache
The returned plugin exposes an invalidate method to clear prefetched entries —
useful after a mutation (e.g. adding to a cart) that would make a cached response stale:
const preloader = preload()
ajax.use(preloader)
// after a cart update:
preloader.invalidate("/cart") // clear one URL
preloader.invalidate() // clear all
Server setup
Prefetch and prerender requests include a Sec-Purpose: prefetch header.
Return a short max-age so responses are cached but don't go stale:
const isPrefetch = req.headers["sec-purpose"]?.startsWith("prefetch")
res.setHeader("Cache-Control", isPrefetch ? "max-age=10" : "no-store")