Offline support pairs the fetch event with the Cache API (The Cache API): install precaches the app shell, and fetch answers from the cache, then the network, then an offline page. waitUntil() keeps the worker alive until a promise settles; respondWith() replaces the browser's own request.
const CACHE = 'shell-v2'; // new name per release; delete old caches on 'activate'
self.addEventListener('install', (e) => e.waitUntil(
caches.open(CACHE).then((c) => c.addAll(['./', 'index.html', 'app.css', 'offline.html']))));
self.addEventListener('fetch', (e) => {
if (e.request.method !== 'GET') return;
e.respondWith(caches.match(e.request).then((hit) => hit ?? fetch(e.request)
.catch(() => caches.match('offline.html'))));
});Offline in headless Chrome 1 , a reload still worked and an uncached URL returned offline.html. For versioning, runtime caching and expiry, most projects use Google's Workbox 13,023 (https://github.com/GoogleChrome/workbox 13,023 ) (MIT, version 7.4.1). Given a config with globDirectory: 'dist/' and runtimeCaching rules (CacheFirst, NetworkFirst, StaleWhileRevalidate), npx workbox-cli generateSW generated a sw.js that precaches every file with a revision hash, so only changed files download again. Vite 25,978 projects use vite-plugin-pwa.