diff --git a/example_sw.js b/example_sw.js new file mode 100644 index 0000000..7cd06cd --- /dev/null +++ b/example_sw.js @@ -0,0 +1,93 @@ +/** + * Note: @ayco/astro-sw integration injects variables `__prefix`, `__version`, & `__assets` + * -- find usage in `astro.config.mjs` integrations + * @see https://ayco.io/n/@ayco/astro-sw + */ +const cacheName = `${__prefix ?? 'app'}-v${__version ?? '000'}` +const addResourcesToCache = async (resources) => { + const cache = await caches.open(cacheName); + console.log('adding resources to cache...', resources) + await cache.addAll(resources); +}; + +const putInCache = async (request, response) => { + const cache = await caches.open(cacheName); + console.log('adding one response to cache...', request) + await cache.put(request, response); +}; + +const cacheFirst = async ({ request, preloadResponsePromise, fallbackUrl }) => { + // First try to get the resource from the cache + const responseFromCache = await caches.match(request); + if (responseFromCache) { + return responseFromCache; + } + + // Next try to use the preloaded response, if it's there + // NOTE: Chrome throws errors regarding preloadResponse, see: + // https://bugs.chromium.org/p/chromium/issues/detail?id=1420515 + // https://github.com/mdn/dom-examples/issues/145 + // To avoid those errors, remove or comment out this block of preloadResponse + // code along with enableNavigationPreload() and the "activate" listener. + const preloadResponse = await preloadResponsePromise; + if (preloadResponse) { + console.info('using preload response', preloadResponse); + putInCache(request, preloadResponse.clone()); + return preloadResponse; + } + + // Next try to get the resource from the network + try { + const responseFromNetwork = await fetch(request.clone()); + // response may be used only once + // we need to save clone to put one copy in cache + // and serve second one + putInCache(request, responseFromNetwork.clone()); + return responseFromNetwork; + } catch (error) { + const fallbackResponse = await caches.match(fallbackUrl); + if (fallbackResponse) { + return fallbackResponse; + } + // when even the fallback response is not available, + // there is nothing we can do, but we must always + // return a Response object + return new Response('Network error happened', { + status: 408, + headers: { 'Content-Type': 'text/plain' }, + }); + } +}; + +const enableNavigationPreload = async () => { + if (self.registration.navigationPreload) { + // Enable navigation preloads! + await self.registration.navigationPreload.enable(); + } +}; + +self.addEventListener('activate', (event) => { + console.log('activating...', event) + event.waitUntil(enableNavigationPreload()); +}); + +self.addEventListener('install', (event) => { + console.log('installing...', event) + event.waitUntil( + addResourcesToCache([ + './', + ...(__assets ?? []) + ]) + ); +}); + +self.addEventListener('fetch', (event) => { + console.log('fetch happened', event.request) + event.respondWith( + cacheFirst({ + request: event.request, + preloadResponsePromise: event.preloadResponse, + fallbackUrl: './', + }) + ); +}); \ No newline at end of file