UNPKG

@aire-ux/aire-overlay

Version:
146 lines (123 loc) 4.72 kB
/// <reference lib="webworker" /> importScripts('sw-runtime-resources-precache.js'); import { clientsClaim, cacheNames, WorkboxPlugin } from 'workbox-core'; import { matchPrecache, precacheAndRoute, getCacheKeyForURL } from 'workbox-precaching'; import { NavigationRoute, registerRoute } from 'workbox-routing'; import { PrecacheEntry } from 'workbox-precaching/_types'; import { NetworkOnly, NetworkFirst } from 'workbox-strategies'; declare var self: ServiceWorkerGlobalScope & { __WB_MANIFEST: Array<PrecacheEntry>; additionalManifestEntries?: Array<PrecacheEntry>; }; self.skipWaiting(); clientsClaim(); declare var OFFLINE_PATH: string; // defined by Webpack/Vite declare var VITE_ENABLED: boolean; // defined by Webpack/Vite // Combine manifest entries injected at compile-time by Webpack/Vite // with ones that Flow injects at runtime through `sw-runtime-resources-precache.js`. let manifestEntries: PrecacheEntry[] = self.__WB_MANIFEST || []; // If injected entries contains element for root, then discard the one from Flow // may only happen when running in development mode, but after a frontend build let hasRootEntry = manifestEntries.findIndex((entry) => entry.url === '.') >= 0; if (self.additionalManifestEntries?.length) { manifestEntries.push(...self.additionalManifestEntries.filter( (entry) => entry.url !== '.' || !hasRootEntry)); } const offlinePath = OFFLINE_PATH; // Compute the registration scope path. // Example: http://localhost:8888/scope-path/sw.js => /scope-path/ const scope = new URL(self.registration.scope); /** * Replaces <base href> in pre-cached response HTML with the service worker’s * scope URL. * * @param response HTML response to modify * @returns modified response */ async function rewriteBaseHref(response: Response) { const html = await response.text(); return new Response(html.replace(/<base\s+href=[^>]*>/, `<base href="${self.registration.scope}">`), response); }; /** * Returns true if the given URL is included in the manifest, otherwise false. */ function isManifestEntryURL(url: URL) { return manifestEntries.some((entry) => getCacheKeyForURL(entry.url) === getCacheKeyForURL(`${url}`)); } /** * A workbox plugin that checks and updates the network connection status * on every fetch request. */ let connectionLost = false; function checkConnectionPlugin(): WorkboxPlugin { return { async fetchDidFail() { connectionLost = true; }, async fetchDidSucceed({ response }) { connectionLost = false; return response } } } const networkOnly = new NetworkOnly({ plugins: [checkConnectionPlugin()] }); const networkFirst = new NetworkFirst({ plugins: [checkConnectionPlugin()] }); if (process.env.NODE_ENV === 'development' && VITE_ENABLED) { self.addEventListener('activate', (event) => { event.waitUntil(caches.delete(cacheNames.runtime)); }); // Cache /VAADIN/* resources in dev mode. Ensure the Vite specific URLs on another port are not handled to avoid excessive logging. registerRoute( ({ url }) => url.port === scope.port && url.pathname.startsWith(`${scope.pathname}VAADIN/`), networkFirst ); } registerRoute( new NavigationRoute(async (context) => { async function serveOfflineFallback() { const response = await matchPrecache(offlinePath); return response ? rewriteBaseHref(response) : undefined; } function serveResourceFromCache() { // Always serve the offline fallback at the scope path. if (context.url.pathname === scope.pathname) { return serveOfflineFallback(); } if (isManifestEntryURL(context.url)) { return matchPrecache(context.request); } return serveOfflineFallback(); }; // Try to serve the resource from the cache when offline is detected. if (!self.navigator.onLine) { const response = await serveResourceFromCache(); if (response) { return response; } } // Sometimes navigator.onLine is not reliable, // try to serve the resource from the cache also in the case of a network failure. try { return await networkOnly.handle(context); } catch (error) { const response = await serveResourceFromCache(); if (response) { return response; } throw error; } }) ); precacheAndRoute(manifestEntries); self.addEventListener('message', (event) => { if (typeof event.data !== 'object' || !('method' in event.data)) { return; } // JSON-RPC request handler for ConnectionStateStore if (event.data.method === 'Vaadin.ServiceWorker.isConnectionLost' && 'id' in event.data) { event.source?.postMessage({ id: event.data.id, result: connectionLost }, []); } });