Agent Wranglers

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.