From c2ab1fc2c6e04c619ba6347bc0cb65e9add72868 Mon Sep 17 00:00:00 2001 From: Ayo Ayco Date: Fri, 2 Aug 2024 15:34:47 +0200 Subject: [PATCH] feat: add simple service worker (#98) --- public/sw.js | 83 +++++++++++++++++++++++++++++++++++++++++++ src/pages/index.astro | 11 +++++- 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 public/sw.js diff --git a/public/sw.js b/public/sw.js new file mode 100644 index 0000000..797f73a --- /dev/null +++ b/public/sw.js @@ -0,0 +1,83 @@ +const addResourcesToCache = async (resources) => { + const cache = await caches.open('v1'); + await cache.addAll(resources); +}; + +const putInCache = async (request, response) => { + const cache = await caches.open('v1'); + 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) => { + event.waitUntil(enableNavigationPreload()); +}); + +self.addEventListener('install', (event) => { + event.waitUntil( + addResourcesToCache([ + './', + './index.html', + './favicon.ico' + ]) + ); +}); + +self.addEventListener('fetch', (event) => { + event.respondWith( + cacheFirst({ + request: event.request, + preloadResponsePromise: event.preloadResponse, + fallbackUrl: './index.html', + }) + ); +}); \ No newline at end of file diff --git a/src/pages/index.astro b/src/pages/index.astro index 8207b00..c455713 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -37,4 +37,13 @@ if (url)