Service Workers and PWAs in 2026
Build offline-first apps with service workers, Cache API, and Background Sync.
Lifecycle Refresher
A service worker has three lifecycle events: install, activate, fetch. Install caches assets. Activate cleans up old caches. Fetch intercepts network requests.
``js
self.addEventListener('install', e => {
e.waitUntil(caches.open('v3').then(c => c.addAll(['/', '/app.js'])));
});
self.addEventListener('activate', e => {
e.waitUntil(caches.keys().then(keys =>
Promise.all(keys.filter(k => k !== 'v3').map(k => caches.delete(k)))
));
});
`
Caching Strategies
- Cache first — for versioned static assets - Network first — for HTML and API - Stale while revalidate — for content that updates but is not time-critical
`js
self.addEventListener('fetch', e => {
if (e.request.mode === 'navigate') {
e.respondWith(networkFirst(e.request));
} else {
e.respondWith(staleWhileRevalidate(e.request));
}
});
`
Background Sync
Queue failed POSTs and replay when connection returns:
`js
self.addEventListener('sync', e => {
if (e.tag === 'flush-outbox') e.waitUntil(flushOutbox());
});
`
Web Push
Service workers receive push events without the page being open. Pair with the Notifications API.
Workbox or Hand-Rolled
Workbox abstracts cache strategies and routing. For complex apps it pays for itself. For 50-line workers, hand-roll.
PWA Install
In 2026, browsers ship richer install prompts. Trigger via the beforeinstallprompt event and call prompt()` after a meaningful user gesture.
For app-shell architecture, combine with [vite build optimization](/blog/vite-build-optimization).