Service Workers & Offline Caching
debt(d7/e5/b5/t7)
Closest to 'only careful code review or runtime testing' (d7) — Lighthouse can flag missing PWA features, but stale HTML caching and bad strategies typically only surface after deployment when users report stale content.
Closest to 'touches multiple files / significant refactor in one component' (e5) — quick_fix says swap to Workbox with network-first for HTML and cache-first for assets, which involves rewriting the SW registration, strategies, and cache versioning logic.
Closest to 'persistent productivity tax' (b5) — service worker lifecycle and cache invalidation shape every deploy and asset-versioning decision in the web frontend context.
Closest to 'serious trap' (t7) — misconception suggests it's easy with Workbox, but the SW update lifecycle (waiting for old tabs, stale HTML, opaque responses, caching authenticated APIs) contradicts intuitive caching behavior.
Also Known As
TL;DR
Explanation
Service Workers run in a separate thread, intercept fetch events, and implement caching strategies: Cache First (serve from cache, fall back to network — ideal for static assets), Network First (try network, fall back to cache — for fresh content), Stale While Revalidate (serve cache immediately, update in background — balance of speed and freshness), Cache Only, and Network Only. Workbox (Google) simplifies service worker patterns. Lifecycle: install (precache static assets), activate (clean old caches), fetch (intercept requests). Service workers require HTTPS (or localhost).
Common Misconception
Why It Matters
Common Mistakes
- Cache First for HTML pages — users see stale content after deploys.
- No cache versioning — old caches never cleaned, storage grows indefinitely.
- Caching third-party resources without CORS headers — cached responses may be opaque.
- Not handling service worker update lifecycle — new service worker waits for old tabs to close.
Code Examples
// Cache everything forever — stale content after deploy:
self.addEventListener('fetch', e => {
e.respondWith(
caches.match(e.request).then(r => r || fetch(e.request))
);
// HTML pages cached forever — users see old version after deploy!
});
// Workbox — strategy per resource type:
import { registerRoute } from 'workbox-routing';
import { CacheFirst, NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies';
// Static assets: cache forever (content-hashed filenames):
registerRoute(({url}) => url.pathname.match(/\.(js|css|woff2)$/),
new CacheFirst({ cacheName: 'assets-v1' }));
// HTML pages: network first, cache fallback:
registerRoute(({request}) => request.mode === 'navigate',
new NetworkFirst({ cacheName: 'pages-v1', networkTimeoutSeconds: 3 }));
// API: stale while revalidate:
registerRoute(({url}) => url.pathname.startsWith('/api/'),
new StaleWhileRevalidate({ cacheName: 'api-v1' }));