Service Worker
SW lifecycle, versioning, auto-activation, navigation preload.
Preconditions
npx @swoff/cli initalready run (or existingswoff.config.json)- Node.js to run the CLI and build script
Status
On by default. The service worker is always generated after swoff init. Navigation caching, strategy-based fetch interception, and cross-tab sync work immediately after registration.
How you integrate it depends on whether your project uses a bundler:
Bundler framework (React, Vue, Svelte, Astro, etc.) — import the modular injector:
import { initServiceWorker } from "./swoff/client-injector";
initServiceWorker();No bundler (no-bundler, HTMX) — include the auto-initializing bundle:
<script src="/swoff/client-injector.bundle.js"></script>Navigation caching, strategy-based fetch interception, and cross-tab sync work immediately after either one-liner.
client-injector (or .bundle.js) is your app's integration point. It wires up SW registration, online/offline detection, a focus listener for reactive cache refresh, and relays SW messages as DOM events (cache-updated, offline-fallback, mutation-sync-progress, etc.).
After npx @swoff/cli generate, everything is already set up.
See the Hybrid SW + Client Model architecture for the design — SW generation phases, content-based versioning, and cache name strategy.
Generated file boundary
Every file under swoff/ is generated from swoff.config.json. The generator places a DO NOT EDIT MANUALLY header on files that are fully managed — editing these files is safe for experimentation, but your changes will be overwritten the next time you run swoff generate.
One exception: swoff/auth/check.ts is intentionally user-editable — it contains the isAuthFailureResponse() predicate you customize to define what constitutes an auth failure for your app.
The extension model:
| Need | How to do it |
|---|---|
| Change strategy, patterns, auth | Edit swoff.config.json, re-run swoff generate |
| Add custom SW behavior (push handler) | Generated swoff/sw/template.js has editable sections |
| Define auth failure detection | Edit swoff/auth/check.ts — it's intentionally user-editable |
| Add custom client-side logic | Import generated modules from your own code — don't edit the modules |
What the generated SW does
The SW registers these event listeners based on your config:
| Event | Purpose |
|---|---|
install | skipWaiting() if auto-activate is enabled — no caching during install |
activate | Claim clients, wipe stale caches, start background precache of remaining assets |
fetch | Intercept requests — runtime cache, strategies, navigation |
message | Reactive cache refresh, auth state sync, mutation control |
push | Display notifications from server push events |
sync | Background sync for queued mutations (if enabled) |
Cache stores
Background precaching
After activation, the SW progressively downloads all configured assets in the background — build output, fallback routes, per-route fallbacks, and the PWA manifest — with IndexedDB checkpoint resume, per-batch progress events, and client-initiated resume on tab focus. See the Precaching guide for the full design.
The install event is minimal — it only calls skipWaiting() if auto-activate is enabled. No caching happens during install, so the SW activates immediately and begins background precaching.
The SW uses three fixed named caches:
| Cache name | Purpose |
|---|---|
"precache" | Precached assets — set at build time from config |
"swoff-runtime" | Runtime-cached API responses (non-HTML) |
"swoff-runtime-html" | Runtime-cached navigation responses (HTML) |
Config
{
"build": {
"swOutput": "public",
"precacheDirs": {
".next/static": {
"prefix": "/_next/static"
},
".next/server/app": {
"prefix": "/",
"matchExtensions": [".html"],
"stripExtensions": [".html"],
"stripSuffixes": ["index"]
}
}
},
"features": {
"serviceWorker": {
"autoActivate": false
}
}
}build.swOutput— directory where the finalswoff.sw.jsis written. Default:"dist".build.precacheDirs— directories to scan for precache assets. Keys are filesystem paths relative to project root. When empty, no directory scanning occurs — only explicit fallback routes are precached. Each entry supports:prefix— URL prefix prepended to each matched file's pathmatchExtensions— only include files with these extensions (e.g.[".html"]); omit for allstripExtensions— remove listed extensions from cache key (e.g.[".html"]strips.html;about.html→/about)stripSuffixes— remove segments likeindexbefore extension (about/index.html→/about)excludeDirs— exclude directories by exact basename. E.g.["node_modules", ".git"]skips all matching directories at any depth.excludeFiles— exclude files by extension glob pattern (basename match). E.g.["*.map", "*.md"]excludes all.mapand.mdfiles.
features.serviceWorker.autoActivate—trueto skip the waiting phase and activate the new SW immediately on install.
Caching strategies and navigation have their own config sections — see Caching Strategies and Navigation Caching.
Framework adapters
This section has one adapter:
useSwoffPrecache
Exposes background precaching state: { status, progress }.
Events listened to:
| Event | Detail shape | Purpose |
|---|---|---|
sw-progress | { percent } | During background precaching |
If your framework already has a useSwoffPrecache adapter (React, Vue, Svelte), the CLI generates it into swoff/adapters/. To create adapters for any other framework, see the Blueprint for the event reference and adapter patterns.
Related
- Comparison: SW Toolkits — Swoff vs Workbox / Serwist / next-pwa