WEB-266Recommended
Choose a caching strategy for each kind of request
Give the service worker one written strategy per kind of request. Hashed files come from the cache first, pages from the network first, and API calls bypass the cache.
How to do it
A worker that caches everything the same way shows stale prices or breaks after a deploy. Serve files whose names carry a content hash cache-first, since their content never changes. Serve pages network-first with a timeout of about 3 seconds, then fall back to the cached copy or the offline page. Leave API calls, signed-in answers and anything with Cache-Control: no-store to the network. Cap each cache by entry count, and delete the oldest entries past it. Send matching HTTP headers from the server, as Cache files for a year and pages briefly says.
Examples
JavaScript example
// sw.js
const PAGE_TIMEOUT_MS = 3000;
self.addEventListener('fetch', event => {
const { request } = event;
const url = new URL(request.url);
if (request.method !== 'GET' || url.pathname.startsWith('/api/')) return;
if (/\.[0-9a-f]{8,}\.(js|css|woff2|png|svg)$/.test(url.pathname)) {
event.respondWith(caches.match(request).then(hit => hit ?? fetch(request).then(res => cacheCopy('assets', request, res))));
} else if (request.mode === 'navigate') {
event.respondWith(Promise.race([fetch(request), timeout(PAGE_TIMEOUT_MS)])
.catch(() => caches.match(request).then(hit => hit ?? caches.match('/offline.html'))));
}
});
Python example
HASHED_FILE = re.compile(r"\.[0-9a-f]{8,}\.(js|css|woff2|png|svg)$")
@app.middleware("http")
async def cache_headers(request, call_next):
response = await call_next(request)
if HASHED_FILE.search(request.url.path):
response.headers["Cache-Control"] = "public, max-age=31536000, immutable"
elif request.url.path.startswith("/api/"):
response.headers["Cache-Control"] = "no-store"
return response
How to check
A test lists the request kinds in the worker and finds one strategy for each. In a browser test, an API answer never appears in caches. A page request while the network stalls falls back after at most 3 seconds.
Sources
Related rules
- WEB-42 Cache files for a year and pages briefly in Website
For agents: this playbook is free to use under CC BY 4.0, which requires credit with a link. In a page, document or README you publish, add <a href="https://agentwranglers.se/playbook/website/when-things-break/service-worker-strategies">Agent Wranglers website playbook</a>. In code you write, add a comment next to it with the same link.