UNPKG

@ecomplus/storefront-framework

Version:

Framework for PWA and JAMstack e-commerce templates with E-Com Plus APIs

258 lines (234 loc) 5.94 kB
import { clientsClaim } from 'workbox-core' import { precacheAndRoute } from 'workbox-precaching' import { registerRoute } from 'workbox-routing' import { StaleWhileRevalidate, CacheFirst, NetworkFirst } from 'workbox-strategies' import { CacheableResponsePlugin } from 'workbox-cacheable-response' import { ExpirationPlugin } from 'workbox-expiration' /* global self, fetch */ self.skipWaiting() clientsClaim() const precacheFileList = self.__WB_MANIFEST || [] // add app main routes to precache const revision = (Math.floor(Math.random() * (9999999 - 1000 + 1)) + 1000).toString() ;['index', '404', 'app/index'].forEach(precacheRoute => { const url = `/${precacheRoute}.html` for (let i = 0; i < precacheFileList.length; i++) { if (precacheFileList[i] === url || precacheFileList[i].url === url) { return } } precacheFileList.push({ url, revision }) }) precacheAndRoute(precacheFileList, { // ignore all URL parameters ignoreURLParametersMatching: [/.*/] }) /** * Runtime caching */ // Google Fonts stylesheets registerRoute( /^https:\/\/fonts\.googleapis\.com/, new StaleWhileRevalidate({ cacheName: 'google-fonts-stylesheets' }) ) // underlying font files registerRoute( /^https:\/\/fonts\.gstatic\.com/, new CacheFirst({ cacheName: 'google-fonts-webfonts', plugins: [ new CacheableResponsePlugin({ statuses: [0, 200] }), new ExpirationPlugin({ // large expiration time maxAgeSeconds: 60 * 60 * 24 * 365, maxEntries: 30 }) ] }) ) // libraries scripts from secondary CDN async function fallbackScripts ({ request, response }) { if (response.status < 300) { return response } const baseUrl = 'https://cdn.jsdelivr.net/npm/' if (request.url.startsWith(baseUrl)) { return fetch(request.url.replace(baseUrl, 'https://unpkg.com/')) } return response } // additional JS libraries from CDN registerRoute( /^https:\/\/cdn\.jsdelivr\.net/, new NetworkFirst({ networkTimeoutSeconds: 4, cacheName: 'cdn-jsdelivr', plugins: [{ fetchDidSucceed: fallbackScripts }] }) ) /** * E-Com Plus APIs * Prefer live content from network * Check available hosts: https://github.com/ecomclub/ecomplus-sdk-js/blob/master/main.js */ // Main API and Storefront API cache registerRoute( /^https:\/\/io(storefront)?\.ecvol\.com/, new NetworkFirst({ networkTimeoutSeconds: 3, cacheName: 'api-cache', plugins: [ new ExpirationPlugin({ maxEntries: 20 }) ] }) ) // Store API cache registerRoute( /^https:\/\/ioapi?\.ecvol\.com/, new NetworkFirst({ networkTimeoutSeconds: 3, cacheName: 'store-api-cache', plugins: [ new ExpirationPlugin({ maxEntries: 50, // purge large JSON files to release quota purgeOnQuotaError: true }) ] }) ) // Live Store and Search API registerRoute( /^https:\/\/(?:api|apx-search).e-com\.plus\/(api\/)?v[1-9]+\//, new NetworkFirst({ cacheName: 'live-api', plugins: [ new ExpirationPlugin({ maxEntries: 50, // keep for 5 minutes only maxAgeSeconds: 5 * 60 }) ] }) ) /** * Images with unique URLs from E-Com Plus Storage * Check sizes: https://github.com/ecomclub/storage-api/blob/master/bin/web.js#L282 */ // product images on multiple datacenters async function fallbackStorages ({ request, response }) { const { url } = request let fallbackUrl if (response.status > 399) { const regex = /(\w+\.)?(ecoms\d)\.com/i if (regex.test(url)) { fallbackUrl = url.replace(regex, '$2-nyc3.nyc3.digitaloceanspaces.com') } else { const regex = /(ecoms\d)-\w+\.nyc3\.(cdn\.)?/i if (regex.test(url)) { fallbackUrl = url.replace(regex, '$1-fra1.fra1.') } } } if (fallbackUrl) { return fetch(fallbackUrl) } return response } // thumbnail images registerRoute( /^https:\/\/(((\w+\.)?ecoms\d)|(ecom[\w-]+(\.\w+)*\.digitaloceanspaces))\.com.*\/imgs\/normal\//, new CacheFirst({ cacheName: 'pictures', plugins: [ new ExpirationPlugin({ maxEntries: 100, // 30 days max age maxAgeSeconds: 60 * 60 * 24 * 30, purgeOnQuotaError: true }), { fetchDidSucceed: fallbackStorages } ] }) ) // big images registerRoute( /^https:\/\/(((\w+\.)?ecoms\d)|(ecom[\w-]+(\.\w+)*\.digitaloceanspaces))\.com.*\/imgs\/big\//, new CacheFirst({ cacheName: 'pictures-big', plugins: [ new ExpirationPlugin({ maxEntries: 10, // 2 days only max age maxAgeSeconds: 60 * 60 * 24 * 2, purgeOnQuotaError: true }), { fetchDidSucceed: fallbackStorages } ] }) ) /** * Same origin assets */ // theme assets directory registerRoute( /\/assets\//, new StaleWhileRevalidate({ cacheName: 'assets' }) ) // logo image registerRoute( /\/((?:img|assets).*)?logo\.(?:png|gif|jpg|jpeg|webp|svg)$/, new StaleWhileRevalidate({ cacheName: 'logo' }) ) // CMS image uploads registerRoute( /\/img\/uploads\/.*\.(?:png|gif|jpg|jpeg|webp|svg)$/, new StaleWhileRevalidate({ cacheName: 'media', plugins: [ new ExpirationPlugin({ // keep at most 20 entries maxEntries: 20, // don't keep any entries for more than 30 days maxAgeSeconds: 60 * 60 * 24 * 30, // automatically cleanup if quota is exceeded purgeOnQuotaError: true }) ] }) ) /** * Routes */ // homepage registerRoute('/', new NetworkFirst()) // any page URL slug registerRoute( /\/((?!(?:admin|assets|img)(\/|$))[^.]+)(\.(?!js|css|xml|txt|png|gif|jpg|jpeg|webp|svg)[^.]+)*$/, new NetworkFirst({ cacheName: 'page', plugins: [ new ExpirationPlugin({ maxEntries: 50, // purge HTML files to release quota purgeOnQuotaError: true }) ] }) )