Loading...
Loading...
Service Worker API implementation guide — registration, lifecycle management, caching strategies, push notifications, and background sync. Use when: (1) creating or modifying service worker files (sw.js), (2) implementing offline-first caching (cache-first, network-first, stale-while-revalidate), (3) setting up push notifications or background sync, (4) debugging service worker registration, scope, or update issues, (5) implementing navigation preload, (6) user mentions 'service worker', 'sw.js', 'offline support', 'cache strategy', 'push notification', 'background sync', 'workbox alternative', or 'PWA caching'.
npx skill4agent add jgamaraalv/ts-dev-kit service-workerimport()importselfServiceWorkerGlobalScoperegister() → Download → Install → [Wait] → Activate → Fetch controlnavigator.serviceWorker.register()self.skipWaiting()clients.claim()// main.js — register from the page
if ("serviceWorker" in navigator) {
const reg = await navigator.serviceWorker.register("/sw.js", { scope: "/" });
// reg.installing | reg.waiting | reg.active
}/sw.js//app/sw.js/app/Service-Worker-Allowed// sw.js
const CACHE_NAME = "v1";
const PRECACHE_URLS = ["/", "/index.html", "/style.css", "/app.js"];
self.addEventListener("install", (event) => {
event.waitUntil(caches.open(CACHE_NAME).then((cache) => cache.addAll(PRECACHE_URLS)));
});waitUntil(promise)self.addEventListener("activate", (event) => {
event.waitUntil(
caches
.keys()
.then((keys) =>
Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key))),
),
);
});self.addEventListener("fetch", (event) => {
event.respondWith(caches.match(event.request).then((cached) => cached || fetch(event.request)));
});respondWith(promise)Responseself.addEventListener("activate", (event) => {
event.waitUntil(self.registration?.navigationPreload.enable());
});
self.addEventListener("fetch", (event) => {
event.respondWith(
(async () => {
const cached = await caches.match(event.request);
if (cached) return cached;
const preloaded = await event.preloadResponse;
if (preloaded) return preloaded;
return fetch(event.request);
})(),
);
});v1v2activateself.skipWaiting()installself.clients.claim()activate// Page → SW
navigator.serviceWorker.controller.postMessage({ type: "SKIP_WAITING" });
// SW → Page (via Clients API)
const clients = await self.clients.matchAll({ type: "window" });
clients.forEach((client) => client.postMessage({ type: "UPDATED" }));
// SW listens
self.addEventListener("message", (event) => {
if (event.data?.type === "SKIP_WAITING") self.skipWaiting();
});response.clone()cache.add()cache.put()event.waitUntil()Service-Worker-AllowedCacheCacheStorageFetchEventClientsServiceWorkerRegistrationServiceWorkerGlobalScopepublic/sw.jspublic/sw.js"use client";
import { useEffect } from "react";
export function ServiceWorkerRegistrar() {
useEffect(() => {
if ("serviceWorker" in navigator) {
navigator.serviceWorker.register("/sw.js");
}
}, []);
return null;
}public//sw.js/chrome://inspect/#service-workersabout:debugging#/runtime/this-firefoxedge://inspect/#service-workers