UNPKG

@enplug/scripts

Version:
145 lines (124 loc) 4.91 kB
/** * Service worker responsible for providing offline support to the WebPlayer * @author Michal Drewniak (michal@enplug.com) */ "use strict"; /** * Offline support configuration. * @type {Object} * @property {string} cacheVersion - Version of the cache. This should be updated any time we want * the previous version of the cache removed. * @property {string} cacheName - Name of the cache. This is usually the same as the application * name or ID. * @property {Array.<string>} = A list of static URLs which should be cached. * @property {Object.<string, number>} - A mapping of URLs (or their parts) to time in minutes. * The URL denotes for which locations cached responses should be refreshed. Time denotes * after which time (in minutes), given response should be refreshed. Time set to 0 means that * a given response should never be cached. */ var config = <% config %>; // End of config. There shouldn't be any need to edit code below. /** * Installs service worker and adds static resources to cache. */ self.addEventListener('install', function (event) { event.waitUntil(caches.open(config.cacheVersion).then((cache) => { return cache.addAll(config.staticResources) .then(() => { console.log(`[<% app_name %>] Offline support service worker v${config.cacheVersion} installed.`); self.skipWaiting(); }) .catch((error) => { console.warn(`[<% app_name %>] Error adding static resources to cache ${config.cacheVersion}.`, error); console.warn(`[<% app_name %>] Static resources: ${JSON.stringify(config.staticResources)}`, config.staticResources); }) })); }); /** * Activate phase. Clears all non-whitelisted cache. */ self.addEventListener('activate', (event) => { var cacheWhitelist = [config.cacheVersion]; event.waitUntil( caches.keys().then(function (cacheNames) { return Promise.all( cacheNames.map(function (cacheName) { if (cacheWhitelist.indexOf(cacheName) === -1) { console.log(`[<% app_name %>] Deleting cache ${cacheName}`); return caches.delete(cacheName); } }) ).then(() => self.clients.claim()); }) ); }); /** * Captures requests and either exectures request to the server or returns a cached version. */ self.addEventListener("fetch", (event) => { function cacheResponse(response) { // Fetching new data resulted in a valid response. Cache it. var responseToCache = response.clone(); caches.open(config.cacheVersion).then( (cache) => { // Cache response and update the time of caching this particular request. if (response && response.ok) { cache.put(cacheUrl, responseToCache); } else { return caches.match(cacheUrl); } }, (error) => { console.warn(`[player-web Unable to cache ${cacheUrl}`, error) } ); // Return the response. return response; } // Ignore POST requests if (event.request.method === 'POST') { return false; } // Get rid of the app token to generalize URL for caching. Having unique URLs for each request // will only make the cache get bigger over time. var cacheUrl = event.request.url.replace(/\?apptoken=[^&]*/g, ''); if (cacheUrl.startsWith('blob:') || cacheUrl.endsWith('.mp4')) { console.log(`[player-web|offline] Caching prevented: URL starts with blob: or ends with .mp4.`); return false; } for (const noCacheUrl of config.noCacheUrls) { if (event.request.url.indexOf(noCacheUrl) >= 0) { return false; } } const originalRequest = event.request; // We need to explicitly change the reqest to CORS request so that cross-domain resources // get properly cached. var fetchRequest = new Request(event.request.url, { headers: originalRequest.headers, mode: 'cors', credentials: 'omit', referrer: 'no-referrer', }); event.respondWith(fetch(fetchRequest) .then((fetchResponse) => { if (!fetchResponse || fetchResponse.status !== 200) { throw Error('CORS request failed.'); } // Propagate correct response down the Promise chain. return fetchResponse; }) // CORS request has failed. We need attempt to refetch the request as no-cors (which is still preferable) // then a failed response. We want to propagate down the Promise chain the response to our no-CORS request. .catch((err) => { console.log(`${TAG} CORS request failed. Attempting fetch original request.`); return fetch(originalRequest); }) .then((response) => cacheResponse(response)) .catch(() => fetch(originalRequest)) .then((response) => cacheResponse(response)) .catch(() => { console.log(`[player-web Unable to fetch ${cacheUrl}. Attempting to return it from cache.`); return caches.match(cacheUrl); })); });