Skip to content

Instantly share code, notes, and snippets.

@kromakollision
Created July 1, 2019 09:08
Show Gist options
  • Save kromakollision/e1b49c1af93d324386536d289305f0f6 to your computer and use it in GitHub Desktop.
Save kromakollision/e1b49c1af93d324386536d289305f0f6 to your computer and use it in GitHub Desktop.
This is a basic (untested) service worker setup.
// This is a basic (untested) service worker setup.
// Thoroughly test all features before using it!
// CACHE KEYS
// update CACHE_KEY to trigger:
// - a new service worker install
// - removal of old caches
// The new service worker will become active after closing all
// website instances where it has been registered
const CACHE_KEY = 'cache-v1';
const CACHE_STATIC = `website-${CACHE_KEY}-static`;
const CACHE_PRELOAD = `website-${CACHE_KEY}-preload`;
const CACHE_DYNAMIC = `website-${CACHE_KEY}-dynamic`;
// CACHE ASSETS
// supply a list of static assets that need to be cached
const cacheStaticAssets = [];
// supply a list of static assets that need to be preloaded and cached
// for example scripts or assets needed on the next page
const cachePreloadAssets = [];
// ACTIONS
const addStaticCaches = () =>
caches
.open(CACHE_STATIC)
.then(cache => cache.addAll(cacheStaticAssets))
.catch(err =>
console.error('Service worker failed to cache static assets.', err)
);
const addPreloadCaches = () =>
caches
.open(CACHE_PRELOAD)
.then(cache => {
// not returning "cache.addAll" allows the preload to fail
// since it's not required content for the current page
cache.addAll(cachePreloadAssets);
})
.catch(err =>
console.error('Service worker failed to preload static assets.', err)
);
const removeOldCaches = () =>
caches
.keys()
.then(cacheNames =>
Promise.all(
cacheNames.map(
cacheName =>
// delete old caches
cacheName.indexOf(CACHE_KEY) === -1 && caches.delete(cacheName)
)
)
)
.catch(err =>
console.error('Service worker failed to remove caches.', err)
);
const checkDynamicCache = request =>
caches
.open(CACHE_DYNAMIC)
.then(cache =>
cache
.match(request)
.then(
response =>
// if the request is cached, return the response
response ||
// if not cached, fetch it online and cache it
fetch(request)
.then(response => {
cache.put(request, response.clone());
return response;
})
.catch(err => console.error('Service worker fetch failed', err))
)
.catch(err =>
console.error('Service workers failed to match request.', err)
)
)
.catch(err =>
console.error('Service worker failed to check dynamic cache.', err)
);
const updateDynamicCache = request =>
caches
.open(CACHE_DYNAMIC)
.then(cache =>
fetch(request)
.then(response => cache.put(request, response))
.catch(err =>
console.error('Service worker failed to fetch cache update.', err)
)
)
.catch(err =>
console.error('Service worker failed to update dynamic cache.', err)
);
// EVENTS
const onInstall = event => {
// console.log('Service worker installed');
event.waitUntil(removeOldCaches());
event.waitUntil(addStaticCaches());
event.waitUntil(addPreloadCaches());
};
const onActivate = event => {
// console.log('Service worker activated');
event.waitUntil(removeOldCaches());
};
const onFetch = event => {
// console.log('Service worker intercepted fetch', event.request);
// skip urls like "chrome-extension://..."
if (event.request.url.indexOf('http') !== 0) return;
// cache only "GET" requests
if (event.request.method !== 'GET') return;
// return the cached fetch or fetch it online
event.respondWith(checkDynamicCache(event.request));
// after serving the cache, update the cache with a new fetch
// to check: does this defeat the purpose of serving a cached version first? It should happen in the background.
event.waitUntil(updateDynamicCache(event.request));
};
const onPush = event => {
console.log('Service worker received push message', event);
};
const onNotificationClick = event => {
console.log('Service worker saw user click on notification', event);
};
const onBackgroundSync = event => {
console.log('Service worker received background sync', event);
};
self.addEventListener('install', onInstall);
self.addEventListener('activate', onActivate);
self.addEventListener('fetch', onFetch);
self.addEventListener('push', onPush);
self.addEventListener('notificationclick', onNotificationClick);
self.addEventListener('sync', onBackgroundSync);
self.onsync = function(evt) {
console.log('Service worker sync', evt);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment