3.4 KiB
service-worker
(no submodules)
Purpose
service-worker.ts is the production Service Worker entrypoint
exposed via the /service-worker subpath. Its only public function,
runPackedResourceServiceWorker(scope, opts?), registers four
handlers — install, activate, fetch, and message — against
the supplied scope. In production the scope is the real
ServiceWorkerGlobalScope; in tests it is the in-memory shim from
sw-shim.ts. Cluster A intentionally caches the packed bytes in
the SW (un-tagged) and lets the PackedResourceManager on the page
do the unpack; Cluster B adds SW-side unpack with range support.
Features
install→scope.skipWaiting()so the new worker activates on the first navigation rather than waiting for every tab to close.activate→ deletes every cache whose name is not the configuredcacheName, then callsscope.clients.claim()so existing tabs start routing through the new worker immediately.fetch→ matchespackedPatterns(default[/\.packed$/, /\?packed=true/]) and intercepts only those URLs. Cache hits are served verbatim; misses trigger an upstream fetch and a cache write taggedX-Unpacked: true.message→ handlesCACHE_CLEAR(deletes the cache) andCACHE_STATUS(replies with{ cacheSize, urls }onevent.ports[0]).- Injectable
fetchfor tests — novi.mockrequired.
Usage: Basic
In your production SW bundle (service-worker.js):
import { runPackedResourceServiceWorker } from "@suaveplan/packer-browser/service-worker";
runPackedResourceServiceWorker(
self as unknown as ServiceWorkerGlobalScope
);
Usage: Advanced
import {
createServiceWorkerShim,
runPackedResourceServiceWorker,
} from "@suaveplan/packer-browser/service-worker";
const scope = createServiceWorkerShim();
runPackedResourceServiceWorker(scope, {
cacheName: "test-cache",
packedPatterns: [/^https:\/\/cdn\.example\.com\/.+\.packed/],
fetch: async (url) => new Response(testBytes),
});
const request = new Request("https://cdn.example.com/a.packed");
const fetchEvent = makeFetchEventLike(request);
scope.dispatchEvent(fetchEvent);
const response = await fetchEvent.responsePromise;
// response.headers.get("X-Unpacked") === "true"
API Reference
runPackedResourceServiceWorker(scope, opts?: RunServiceWorkerOptions): void.RunServiceWorkerOptions:cacheName?: string— default"packed-resources-v1".packedPatterns?: ReadonlyArray<RegExp>— default[/\.packed$/, /\?packed=true/].fetch?: FetchLike— defaultglobalThis.fetch.
- Errors raised inside the fetch handler are
PackerBrowserErrorwithLOAD_FAILED(network) orRESOURCE_NOT_FOUND(non-2xx) codes; they propagate out ofrespondWithas a rejected promise.
Implementation Notes
The SW deliberately does not call into PackedResourceManager from
inside its scope — the manager owns Blob URL allocation, which is a
page-scope concern (a SW that calls URL.createObjectURL produces
URLs the page cannot resolve). The SW's role is purely to cache the
packed bytes and short-circuit re-fetch. The page-side manager
sees the cached response (or a fresh network response) and runs the
unpack. This split keeps the SW small enough to register on a flaky
connection without bundling the entire Unpacker pipeline.