| name | pwa-service-worker |
| description | Service worker management, offline support, cache strategies, and SW debugging. |
Service Worker Skill
When to use this skill
- Debugging service worker issues (stale cache, offline behavior)
- Updating cache strategies
- Adding offline support for specific routes
- Clearing service worker cache during development
- Understanding the caching layers
Note: This portfolio has a hand-written service worker (public/sw.js) but is NOT a PWA. There is no manifest.json.
Service worker reference
File: public/sw.js
Current version: v4
Cache strategy by path:
| Path pattern | Strategy | Notes |
|---|
_next/static/ | Network-first | Prevents stale chunks |
_next/data/ | Network-first | Fresh page data |
/api/ | Network-only | Never cache API responses |
fonts/ | Cache-first | Static, immutable assets |
images/ | Cache-first | Static images |
| Other | Stale-while-revalidate | Balanced approach |
Workflow
1. Clear service worker cache (development)
Chrome DevTools:
- Open DevTools → Application tab
- Click "Service Workers" in the left sidebar
- Click "Unregister" on the active worker
- Click "Storage" → "Clear site data"
- Hard refresh:
Ctrl+Shift+R (Windows) / Cmd+Shift+R (Mac)
Via code (for users):
The service worker includes a version check. When the version changes, the old cache is automatically cleared in the install event handler.
2. Update service worker version
When making changes to public/sw.js:
- Update the
CACHE_VERSION constant:
const CACHE_VERSION = 'v5';
- The old cache is automatically cleaned up on next visit
- Users get a fresh install with the new cache
3. Add a new route to cache
Add to the urlsToCache array in the install handler:
const urlsToCache = [
'/',
'/offline',
'/fonts/inter-var.woff2',
'/new-static-asset.js',
];
Change cache strategy for a path:
In the fetch handler, add a new case:
if (url.pathname.startsWith('/new-path/')) {
event.respondWith(
fetch(event.request)
.then(response => {
const responseClone = response.clone();
caches.open(CACHE_NAME).then(cache => {
cache.put(event.request, responseClone);
});
return response;
})
.catch(() => caches.match(event.request))
);
return;
}
4. Cache strategies explained
Cache-first (static assets):
Request → Cache hit? → Yes → Return cached
→ No → Fetch → Cache → Return
Best for: fonts, images, immutable assets
Network-first (API, dynamic):
Request → Fetch → OK? → Return response → Cache
→ Fail? → Cache hit? → Return cached
→ No? → Offline fallback
Best for: API calls, dynamic pages, _next/static/
Stale-while-revalidate:
Request → Cache hit? → Yes → Return cached + fetch in background
→ No → Fetch → Cache → Return
Best for: pages, HTML, semi-static content
5. Offline support
Current offline page: /offline (if configured)
To add offline support for a route:
- Add the route to
urlsToCache in the install handler
- The service worker will serve from cache when offline
- Consider serving a fallback page for uncached routes
6. Debugging service worker issues
Problem: Stale content after deployment
Problem: Page shows old version
- Check
CACHE_VERSION was incremented in sw.js
- Clear all caches manually
- Unregister the service worker
- Hard refresh
Problem: Assets not loading
- Check the service worker console: DevTools → Application → Service Workers → "Start" script
- Look for errors in the SW console (separate from page console)
- Check if the asset path is in the cache
Problem: SW not registering
- Check
public/sw.js exists
- Check registration code in the app
- Verify no errors in the page console
- SW only works on HTTPS (or localhost)
7. Performance impact
Service workers add minimal overhead:
- Registration: ~1ms
- Install: runs in background, no impact on page load
- Fetch interception: ~0.1ms per request
- Cache lookups: ~0.5ms per asset
Keep the SW lean:
- Don't cache large files in the install handler
- Use
network-first for frequently updated content
- Limit cache size (current SW doesn't enforce a limit -- consider adding one)
Common mistakes
- Forgetting to increment
CACHE_VERSION after changes
- Caching API responses (always use network-only for
/api/)
- Not testing in incognito (old SW may be cached)
- Deploying SW changes without bumping the version
- Caching third-party resources (unreliable, can break)
Quick reference
Delivery checks