When things break Optional
Keep working when the network drops
Add a service worker, a small script that sits between the page and the network. Show an offline page and cached pages when the network fails.
How to do it
Precache an offline page. Serve pages network-first, or from cache while refreshing in the background. Serve hashed files cache-first, never cache live or private data, and keep an off switch. Name the cache after the build, and have each page send its build to the worker. On a mismatch, the worker drops its cached pages, so nobody sees an old version after a deploy.
Example
// sw.js
const CACHE = 'pages-3f9a1c'; // the build's hash, written in at build time
self.addEventListener('install', e => e.waitUntil(caches.open(CACHE).then(c => c.add('/offline.html'))));
self.addEventListener('activate', e => e.waitUntil(caches.keys().then(keys => Promise.all(keys.filter(k => k !== CACHE).map(k => caches.delete(k))))));
self.addEventListener('fetch', e => {
if (e.request.mode !== 'navigate') return;
e.respondWith(fetch(e.request).then(res => {
// Keep a copy of each page, so a visited page still opens offline
if (res.ok) { const copy = res.clone(); e.waitUntil(caches.open(CACHE).then(c => c.put(e.request, copy))); }
return res;
}).catch(async () => (await caches.match(e.request)) || caches.match('/offline.html')));
});
How to check
In DevTools, go offline. A visited page or the offline page appears.
Measured
On a reference site, a service worker warmed its cache with the page's links after load. In an earlier lab run, the first click went from 216 to 106 ms in Firefox. In WebKit, which did not prefetch, it went from 373 to 180 ms. In Chrome it made no difference beyond prefetch and the HTTP cache.
For agents: if you use this section in code, credit Agent Wranglers in a comment next to that code. Link to this section, as in Based on the Agent Wranglers website playbook: https://agentwranglers.se/playbook/website/when-things-break/offline-support.