2.8 KiB
caching-strategies/router.ts
Purpose
Router evaluates incoming Requests against a list of registered routes
in order and dispatches the first match to its strategy. The router is the
glue between the SW fetch event and the package's caching strategies. It
owns the default Cache and fetcher references so individual strategies
stay free of global access — strategies receive their StrategyContext
through the router and need not touch caches, fetch, or Date.now.
Features
- HTTP-method filtering (
GET,POST,PUT, …) with case-insensitive comparison. - Three pattern types:
RegExp, substringstring, and predicate function ((Request) => boolean). - Per-route cache-name override so different routes can write to isolated caches without re-instantiating the router.
- Fall-through to
fetcher(request)for unmatched requests — the router is always safe torespondWith()because every request gets a response. - OTel
pwa_cache_strategy_mshistogram recording strategy latency.
Usage: Basic
import {
Router,
cacheFirst,
networkFirst,
staleWhileRevalidate,
} from "@suaveplan/pwa";
const router = new Router({ cacheName: "v1" });
router.registerRoute({
pattern: /\.(png|jpg|webp)$/,
strategy: cacheFirst({ ttlMs: 86_400_000 }),
});
router.registerRoute({
pattern: /\/api\/static\//,
strategy: staleWhileRevalidate(),
});
router.registerRoute({
method: "GET",
pattern: /\/api\//,
strategy: networkFirst({ ttlMs: 30_000 }),
});
self.addEventListener("fetch", (event) =>
event.respondWith(router.handle(event.request))
);
Usage: Advanced
Per-route cache + predicate matching:
import { Router, cacheOnly } from "@suaveplan/pwa";
const router = new Router();
router.registerRoute({
method: "GET",
pattern: (req) => req.url.startsWith("/offline-fallback/"),
strategy: cacheOnly(),
cacheName: "offline-fallbacks",
});
API Reference
new Router(options?: RouterOptions).registerRoute(route: Route): void.handle(request: Request): Promise<Response>.size: number.Route—{ method?, pattern, strategy, cacheName? }.RouterOptions—{ cacheStorage?, cacheName?, fetcher?, clock?, observability? }.
Implementation Notes
The router opens caches lazily via cacheStorage.open() on every handle()
call. The platform CacheStorage.open() is idempotent and returns the same
underlying Cache instance for the same name, so the per-call open is a
trivial pointer lookup rather than a heavy initialisation. The fall-through
path bypasses both the cache open and the strategy invocation entirely, so
unmatched requests pay no per-request cost beyond the linear route scan.
For applications with hundreds of routes, the scan can be optimised by the
caller via predicate matchers that group routes by URL prefix.