Designing a Minimal HTML5 Service Worker for Offline Caching
A concise architecture note for implementing a minimal HTML5 Service Worker that caches core assets and serves them offline, covering requirements, design, trust boundaries, checks, failure modes, verification, limits, and rollback.
07 Sept 2025, 08:58 UTC

Requirements
The page must be served over HTTPS (or localhost for development) and the service‑worker script must be same‑origin. Registration is asynchronous and returns a promise that resolves to a ServiceWorkerRegistration object.
Smallest Suitable Design
Register a minimal worker file (e.g., /sw.js) that caches core assets on install and serves them from the cache on fetch when the network is unavailable.
// sw.js
const CACHE = 'v1-core';
const CORE = ['/', '/index.html', '/styles.css', '/app.js'];
self.addEventListener('install', e => {
e.waitUntil(caches.open(CACHE).then(cache => cache.addAll(CORE)));
});
self.addEventListener('fetch', e => {
if (e.request.method !== 'GET') return;
e.respondWith(caches.match(e.request).then(resp => resp || fetch(e.request)));
});
Trust and Data Boundaries
The worker runs in a separate thread with no direct DOM access. Communication with the page happens via postMessage. Its scope limits the URLs it can control, enforcing the same‑origin rule.
Operational Checks
After registration you can inspect state with navigator.serviceWorker.getRegistrations(), listen for controllerchange to detect when a new worker takes control, and call registration.update() to check for script updates.
Failure Modes and Design‑Change Conditions
- Registration fails if the page is not secure (non‑HTTPS, non‑localhost).
- If the worker throws during
installoractivateit becomes redundant and will not control the page. - A mis‑configured
fetchhandler can block legitimate requests or serve stale data. - Adding Background Sync or Push requires extra permissions and manifest entries, changing the base design.
Verification
- Check support:
if ('serviceWorker' in navigator) { … }. - Register:
navigator.serviceWorker.register('/sw.js').then(reg => console.log('Registered', reg)).catch(err => console.error('Registration failed', err)); - Open DevTools → Application → Service Workers to see status (installed, activating, active) and to trigger updates or unregister.
- Simulate offline (DevTools → Network → Offline) and reload; verify the page loads and that fetch events are served from the cache as defined in the worker.
Limitations
- Improper caching can serve stale content indefinitely; implement versioning (cache name) or cache‑busting to avoid outdated assets.
- A buggy worker can break navigation or cause redirect loops; debugging may require unregistering or using DevTools.
- The worker intercepts all network requests within its scope; an overly broad
fetchcan accidentally block requests or expose sensitive data if not scoped correctly.
Rollback (Unregistering the Worker)
Because registration adds a worker to the browser, you can revert the change by unregistering:
navigator.serviceWorker.getRegistrations().then(regs => {
regs.forEach(reg => reg.unregister().then(() => console.log('Unregistered')));
});
After unregistering, reload the page to confirm the worker no longer appears in the Service Workers pane.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.