SwoffSwoff

Service Worker

SW lifecycle, versioning, auto-activation, navigation preload.

Preconditions

  • npx @swoff/cli init already run (or existing swoff.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:

NeedHow to do it
Change strategy, patterns, authEdit swoff.config.json, re-run swoff generate
Add custom SW behavior (push handler)Generated swoff/sw/template.js has editable sections
Define auth failure detectionEdit swoff/auth/check.ts — it's intentionally user-editable
Add custom client-side logicImport 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:

EventPurpose
installskipWaiting() if auto-activate is enabled — no caching during install
activateClaim clients, wipe stale caches, start background precache of remaining assets
fetchIntercept requests — runtime cache, strategies, navigation
messageReactive cache refresh, auth state sync, mutation control
pushDisplay notifications from server push events
syncBackground 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 namePurpose
"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 final swoff.sw.js is 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 path
    • matchExtensions — only include files with these extensions (e.g. [".html"]); omit for all
    • stripExtensions — remove listed extensions from cache key (e.g. [".html"] strips .html; about.html/about)
    • stripSuffixes — remove segments like index before 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 .map and .md files.
  • features.serviceWorker.autoActivatetrue to 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:

EventDetail shapePurpose
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.

On this page