UNPKG

baazjs

Version:
164 lines (147 loc) 4.92 kB
import { PREFETCH_IMAGES } from '../../constants/swMessageTypes'; import { isFastNetwork } from './networkUtils'; import { THIRTY_DAYS, CATALOG_CACHE_NAME } from '../defaults'; import { registerMessageHandler } from './messageHandler'; const getWidth = url => Number(new URLSearchParams(url.search).get('width')); const isCatalogImage = ({ url }) => url.pathname.startsWith('/media/catalog'); /** * isResizedCatalogImage is route checker for workbox * that returns true for a valid catalog image URL. * * @param {url: URL, event: FetchEvent} workboxRouteObject * * @returns {boolean} */ export const isResizedCatalogImage = ({ url }) => isCatalogImage({ url }) && !isNaN(getWidth(url)); /** * This function tries to find same or a larger image * from the catalog cache storage. * * @param {URL} url * * @returns {Promise | undefined} A promise that resolves to a valid response * object from cache or undefined if the a match could not be found. */ export const findSameOrLargerImage = async url => { const requestedWidth = getWidth(url); const requestedFilename = url.pathname.split('/').reverse()[0]; const cache = await caches.open(CATALOG_CACHE_NAME); const cachedURLs = await cache.keys(); const cachedSources = await cachedURLs.filter(({ url }) => url.includes(requestedFilename) ); // Find the cached version of this image that is closest to the requested // width without going under it. let best = { difference: Infinity, candidate: null }; for (const candidate of cachedSources) { const width = getWidth(new URL(candidate.url)); /** * If the cached image has no resize param continue because * we can't safely use it */ if (isNaN(width)) { continue; } const difference = width - requestedWidth; /** * If cached image is smaller than requested continue because * we can't safely use it */ if (difference < 0) { continue; } /** * If the cached image is same as what we are looking for, return. */ if (difference === 0) { return await cache.match(candidate); } /** * If the cached image is larger than what we saw till now, update * the candidate and keep looking for a better version. */ if (difference < best.difference) { best = { difference, candidate }; } } if (best.candidate) { const bestCachedResponse = await cache.match(best.candidate); console.log( `ServiceWorker responding to GET ${ url.pathname } at ${requestedWidth}w with cached version ${ best.difference }px larger: ${bestCachedResponse.url}` ); return bestCachedResponse; } }; const fetchAndCacheImage = imageURL => fetch(imageURL).then(response => caches .open(CATALOG_CACHE_NAME) .then(cache => cache.put(imageURL, response.clone())) .then(() => response) ); const fetchIfNotCached = imageURL => new Promise(resolve => { caches.match(imageURL).then(res => { res ? resolve(res) : resolve(fetchAndCacheImage(imageURL)); }); }); const handleImagePreFetchRequest = (payload, event) => { if (isFastNetwork()) { return Promise.all(payload.urls.map(fetchIfNotCached)) .then(responses => { event.ports[0].postMessage({ status: 'done' }); return responses; }) .catch(err => { event.ports[0].postMessage({ status: 'error', message: JSON.stringify(err) }); return null; }); } else { event.ports[0].postMessage({ status: 'error', message: `Slow Network detected. Not pre-fetching images. ${ payload.urls }` }); return null; } }; /** * This function registers all message handlers related to * image prefetching. * * Messages it registers handlers to: * * 1. PREFETCH_IMAGES */ export const registerImagePreFetchHandler = () => { registerMessageHandler(PREFETCH_IMAGES, handleImagePreFetchRequest); }; /** * This function creates a handler that workbox can use * to handle all catalog images. */ export const createCatalogCacheHandler = () => new workbox.strategies.CacheFirst({ cacheName: CATALOG_CACHE_NAME, plugins: [ new workbox.expiration.Plugin({ maxEntries: 60, maxAgeSeconds: THIRTY_DAYS }), new workbox.cacheableResponse.Plugin({ statuses: [0, 200] }) ] });