register-service-worker
A tiny script that wires up service worker registration with lifecycle hooks for offline-ready web apps.
Repository Health
Technical Analysis
register-service-worker is a small helper script that handles the boilerplate of registering a service worker in the browser, exposing named lifecycle hooks so an app can react to registration, caching, and update events without writing raw Service Worker API plumbing directly. It began life as the service worker registration snippet bundled with Create React App and was later extracted into its own package, becoming the registration layer used by tools like Vue CLI’s PWA plugin.
Calling register(swUrl, hooks) checks whether the browser supports service workers, distinguishes between localhost development (where it verifies the worker file actually exists and has the right content type before registering) and production, and then emits ready, registered, cached, updatefound, updated, offline, and error callbacks as the underlying ServiceWorkerRegistration progresses through its lifecycle. A companion unregister() function removes any active registration. The whole implementation is a single dependency-free ES module, meant to be consumed through a bundler rather than used standalone in a plain script tag.
What You Get
- A single
register(swUrl, hooks)call that registers a service worker and wires up hooks for every stage of its lifecycle - Automatic localhost detection that verifies the service worker file exists (and has a JS content-type) before registering, avoiding confusing dev-mode errors
- An
unregister()helper to tear down an active service worker registration - Zero runtime dependencies and a tiny, single-file implementation that ships as an ES module
- TypeScript type definitions (
index.d.ts) for theHooksobject and both exported functions
Common Use Cases
- Adding offline support to a client-rendered SPA built with webpack, Vite, or another ES-module bundler
- Showing a “new content is available, please refresh” toast when the
updatedhook fires after a service worker update installs - Powering the service worker registration step baked into scaffolding tools like Vue CLI’s PWA plugin
- Detecting when a service worker fails to register (404, wrong content-type, offline) during local development
Under The Hood
Architecture
The entire package is one small ES module (src/index.js) exporting register and unregister. Control flow is a straightforward branch: on load, register() waits for the window load event, then checks isLocalhost() to pick between checkValidServiceWorker (which fetches the worker file first to validate it exists and is served as JavaScript before registering, specifically to give clearer errors during local development) and registerValidSW (which registers directly in production). Both paths converge on the same emit(hook, ...args) closure that looks up and invokes the matching callback from the hooks object, and both attach .catch(error => handleError(...)) to surface offline versus generic errors separately. There’s no internal state beyond the module-level waitWindowLoad promise, and no abstraction layers beyond this single dispatch function, which keeps the whole thing easy to read in one pass.
Tech Stack
The distributable index.js is generated from src/index.js via a tiny build script (scripts/build.js) that runs the source through buble, a lightweight ES2015+-to-ES5 transpiler chosen over Babel for its smaller footprint, with transforms.modules disabled so ES import/export syntax is preserved in the output for bundler consumption. conventional-changelog-cli generates CHANGELOG.md on publish. There are no runtime dependencies at all — the only two devDependencies are buble and conventional-changelog-cli — and the package targets any project with an ES-module-aware bundler (webpack, Vite, Rollup) rather than being usable as a bare <script> include.
Code Quality
There are no test files, no CI configuration, and no linter or formatter config anywhere in the repository — quality is enforced entirely by the small surface area and the maintainer’s own review. Error handling is deliberate rather than absent: a dedicated handleError function distinguishes navigator.onLine === false (emits offline) from other failures (emits error), and the localhost validation path explicitly checks both HTTP status and content-type before treating a URL as a real service worker. Naming is plain and descriptive (registerValidSW, checkValidServiceWorker), and comments explain non-obvious browser-compatibility decisions (e.g. why a Promise polyfill fallback exists for waitWindowLoad), but without automated tests correctness rests on manual verification and the project’s long real-world usage history.
API Design
The public surface is deliberately minimal: two functions, register(swUrl, hooks) and unregister(), with hooks as a single plain object of named callbacks rather than an event emitter or class instance to manage. This keeps integration to a handful of lines with no setup beyond calling register() once at app startup, and the bundled index.d.ts gives TypeScript users full autocomplete on the hook names and their ServiceWorkerRegistration argument. The tradeoff for that simplicity is a very small README with a single usage example and no dedicated docs site, so nuances like hook ordering or the localhost-specific validation behavior are only discoverable by reading the source.
Used by 2 apps in this directory
ezBookkeeping
Invoicing Finance
Lightweight self-hosted personal finance manager with AI receipt scanning, multi-currency support, and MCP integration for complete data privacy.
Vikunja
Project Management
Self-hosted task management with natural-language quick-add, multiple views, and a fully documented REST API — your tasks, your infrastructure, zero lock-in.