website-theme/static/serviceworker.js

136 lines
3.6 KiB
JavaScript
Raw Normal View History

let version = 'v1::';
let cacheName = 'website';
2024-10-20 12:36:35 -04:00
let offlinePage = '/offline/';
let offlineFundamentals = [offlinePage, '/'];
let maxItems = 100;
2024-10-20 12:05:59 -04:00
function addFundamentals() {
return caches.open(version + cacheName)
.then(cache => cache.addAll(offlineFundamentals))
}
// Cache the page(s) that initiate the service worker
function cacheClients() {
return clients.matchAll({
includeUncontrolled: true
})
.then(allClients => allClients.map(client => client.url))
2024-10-20 12:13:26 -04:00
.then(pages => Promise.all([pages, caches.open(cacheName)]))
2024-10-20 12:05:59 -04:00
.then(([pages, cache]) => cache.addAll(pages))
}
// Remove caches whose name is no longer valid
function clearInvalidatedCaches() {
return caches.keys()
.then( keys => {
return Promise.all(keys
.filter(key => !key.includes(version))
.map(key => caches.delete(key))
);
});
}
2024-10-20 10:56:57 -04:00
2024-10-20 12:05:59 -04:00
function trimCache(name, maxItems) {
return caches.open(name)
2024-10-20 12:13:26 -04:00
.then(cache => Promise.all([cache, cache.keys()]))
2024-10-20 12:05:59 -04:00
// Make sure offlineFundamentals don't get deleted
2024-10-20 12:18:24 -04:00
.then(([cache, keys]) => [
cache,
keys.filter(key => !offlineFundamentals.includes(key)),
keys.length - maxItems
])
.then(([cache, possibleDelete, numToDelete]) => {
2024-10-20 12:05:59 -04:00
// Trim cache until we are of the right size
deleteInProgress = []
2024-10-20 12:18:24 -04:00
for (let i = 0; i < numToDelete; i++) {
2024-10-20 10:56:57 -04:00
// Keep track of each delete
2024-10-20 12:05:59 -04:00
deleteInProgress.push(cache.delete(possibleDelete[i]));
}
2024-10-20 10:56:57 -04:00
2024-10-20 12:05:59 -04:00
// Return when everything is resolved
return Promise.all(deleteInProgress);
2024-10-20 10:56:57 -04:00
})
}
2024-10-20 12:05:59 -04:00
self.addEventListener('install', function (event) {
// Cache offline fundamentals
event.waitUntil(
addFundamentals()
.then(() => cacheClients())
.then(() => skipWaiting())
)
});
// Listens for trimCache command which occurs on page load
self.addEventListener('message', event => {
2024-10-19 21:52:15 -04:00
if (event.data.command == 'trimCache') {
trimCache(version + cacheName, maxItems);
}
});
// If the version changes, invalidate the cache
self.addEventListener('activate', function (event) {
2024-10-19 21:52:15 -04:00
event.waitUntil(
2024-10-20 12:05:59 -04:00
clearInvalidatedCaches()
.then(() => clients.claim())
2024-10-19 21:52:15 -04:00
);
});
2024-10-20 12:05:59 -04:00
if (registration.navigationPreload) {
addEventListener('activate', event => {
event.waitUntil(
registration.navigationPreload.enable()
);
});
}
// Listen for request events
self.addEventListener('fetch', function (event) {
2024-10-20 12:05:59 -04:00
const request = event.request;
2024-10-20 10:56:57 -04:00
let isRequestType = function(name) {
return request.headers
.get('Accept')
.includes(name);
}
2024-10-20 12:36:35 -04:00
// Always fetch non-GET requests from the network
if (request.method !== 'GET') {
// Present offline page when failed to
// fetch a HTML page
if (isRequestType('text/html')) {
event.respondWith(
fetch(request)
.catch(() => caches.match(offlinePage))
);
}
return;
}
// Network-first Approach
event.respondWith(
2024-10-19 21:52:15 -04:00
// Attepmt to grab the latest copy from the network
2024-10-20 12:05:59 -04:00
Promise.resolve(event.preloadResponse)
.then(preloadResponse => preloadResponse || fetch(request))
.then(response => {
// If successful, create a copy of the response
2024-10-19 21:52:15 -04:00
// and save it to the cache
// Note: Ignore badges
2024-10-20 10:56:57 -04:00
if (!request.url.includes("/badges")) {
2024-10-19 21:52:15 -04:00
let cacheCopy = response.clone();
2024-10-20 12:05:59 -04:00
event.waitUntil(
caches.open(version + cacheName)
.then(cache => cache.put(request, cacheCopy))
);
2024-10-19 21:52:15 -04:00
}
return response;
})
2024-10-20 12:05:59 -04:00
// Check the cache
.catch(error =>
caches.match(request)
// Show offline page for HTML pages if cache miss
.then(response => isRequestType('text/html')? response || caches.match(offlinePage) : response)
)
);
});