Service Worker
To get Toapi’s offline / tag-based revalidation behavior, add a service worker
built by vite-plugin-pwa in
injectManifest mode. The two plugins compose cleanly: @toapi/vite-plugin
redirects the client build to dist/client/, which is exactly where VitePWA
emits sw.js, and the production server bundle is built separately so nothing
leaks across.
Installation
Section titled “Installation”pnpm add -D vite-plugin-pwaVite config
Section titled “Vite config”import { defineConfig } from "vite";import toapi from "@toapi/vite-plugin";import { VitePWA } from "vite-plugin-pwa";
export default defineConfig({ plugins: [ toapi(), VitePWA({ strategies: "injectManifest", srcDir: "src", filename: "service-worker.ts", injectRegister: "auto", devOptions: { enabled: true, type: "module" }, // optional, pass-through to VitePWA: // manifest: { name: "My App", short_name: "App", ... }, }), ],});Setting devOptions.enabled: true makes the service worker run during
vite dev as well. Without it the SW only runs in vite preview and
production.
Service worker
Section titled “Service worker”import { handleTapiRequest, listenForInvalidations, cleanup,} from "@toapi/worker";
declare const self: ServiceWorkerGlobalScope;
self.addEventListener("activate", (event) => { // Drop cache entries that have been expired longer than 7 days, // remove orphans, and rebuild the tags index. event.waitUntil(cleanup({ maximumStaleAge: 60 * 60 * 24 * 7 }));});
self.addEventListener("fetch", (event) => { const url = new URL(event.request.url); if ( url.pathname.startsWith("/api") && !url.pathname.startsWith("/api/__tapi") ) { event.respondWith(handleTapiRequest(event.request)); }});
listenForInvalidations({ url: "/api/__tapi/invalidations" });TypeScript
Section titled “TypeScript”Add "WebWorker" to the lib array in tsconfig.json so TypeScript
recognizes ServiceWorkerGlobalScope and related globals:
{ "compilerOptions": { "lib": ["ESNext", "DOM", "WebWorker"] }}- Adjust the
/apipath checks in the service worker to match thebasePathyou pass totoapi(). cleanup’smaximumStaleAgeis a grace period, in seconds, past a cache entry’sexpiresAtbefore it is actually deleted on the next SW activation.
For the full service-worker API, see the
@toapi/worker package.