diff --git a/public/service-worker.js b/public/service-worker.js index 79dca28..07b88fd 100644 --- a/public/service-worker.js +++ b/public/service-worker.js @@ -1,9 +1,14 @@ -const CACHE_VERSION = 'synapse-cache-v1' -const PRECACHE_ASSETS = ['/', '/index.html'] +const CACHE_VERSION = 'synapse-cache-v2' +const PRECACHE_ASSETS = ['/'] +const ASSET_PATTERN = + /\.(?:js|css|woff2?|ttf|otf|png|jpg|jpeg|gif|svg|webp|ico|json|txt)$/i self.addEventListener('install', (event) => { event.waitUntil( - caches.open(CACHE_VERSION).then((cache) => cache.addAll(PRECACHE_ASSETS)).then(() => self.skipWaiting()) + caches + .open(CACHE_VERSION) + .then((cache) => cache.addAll(PRECACHE_ASSETS)) + .then(() => self.skipWaiting()), ) }) @@ -18,13 +23,77 @@ self.addEventListener('activate', (event) => { return caches.delete(key) } return undefined - }) - ) + }), + ), ) - .then(() => self.clients.claim()) + .then(() => self.clients.claim()), ) }) +const isHtmlRequest = (request) => { + if (request.mode === 'navigate') return true + if (request.destination === 'document') return true + const acceptHeader = request.headers.get('accept') || '' + return acceptHeader.includes('text/html') +} + +const shouldHandleAsset = (requestURL, request) => { + if (ASSET_PATTERN.test(requestURL.pathname)) { + return true + } + return ['script', 'style', 'font', 'image'].includes(request.destination) +} + +const cacheNetworkFirst = async (request) => { + const cache = await caches.open(CACHE_VERSION) + + try { + const networkResponse = await fetch(request) + + if ( + networkResponse && + networkResponse.status === 200 && + (networkResponse.type === 'basic' || networkResponse.type === 'cors') + ) { + cache.put(request, networkResponse.clone()) + } + + return networkResponse + } catch (error) { + const cachedResponse = await cache.match(request) + if (cachedResponse) { + return cachedResponse + } + throw error + } +} + +const networkFirstHtml = async (request) => { + const cache = await caches.open(CACHE_VERSION) + + try { + const response = await fetch(request) + + if (response && response.status === 200) { + cache.put(request, response.clone()) + } + + return response + } catch (error) { + const cachedResponse = await cache.match(request) + if (cachedResponse) { + return cachedResponse + } + + const fallback = await cache.match('/') + if (fallback) { + return fallback + } + + throw error + } +} + self.addEventListener('fetch', (event) => { const { request } = event @@ -38,35 +107,12 @@ self.addEventListener('fetch', (event) => { return } - event.respondWith( - (async () => { - const cachedResponse = await caches.match(request) - if (cachedResponse) { - return cachedResponse - } - - try { - const networkResponse = await fetch(request) - - if ( - networkResponse && - networkResponse.status === 200 && - networkResponse.type === 'basic' - ) { - const cache = await caches.open(CACHE_VERSION) - cache.put(request, networkResponse.clone()) - } - - return networkResponse - } catch (error) { - if (request.mode === 'navigate') { - const fallback = await caches.match('/') - if (fallback) { - return fallback - } - } - throw error - } - })() - ) + if (isHtmlRequest(request)) { + event.respondWith(networkFirstHtml(request)) + return + } + + if (shouldHandleAsset(requestURL, request)) { + event.respondWith(cacheNetworkFirst(request)) + } })