diff --git a/config/pwa.ts b/config/pwa.ts index 19c82b7f..f0708d19 100644 --- a/config/pwa.ts +++ b/config/pwa.ts @@ -14,7 +14,7 @@ export const pwa: VitePWANuxtOptions = { manifest: false, injectManifest: { globPatterns: ['**/*.{js,json,css,html,txt,svg,png,ico,webp,woff,woff2,ttf,eot,otf,wasm}'], - globIgnores: ['emojis/**', 'shiki/**', 'manifest**.webmanifest'], + globIgnores: ['emojis/**', 'shiki/**', 'manifest**.webmanifest', 'pwa-*.png', 'maskable-icon.png', 'shortcuts/**', 'screenshots/**'], manifestTransforms: [(entries) => { const manifest = entries.map((entry) => { if (entry.url.length > 1 && entry.url[0] !== '/') diff --git a/service-worker/sw.ts b/service-worker/sw.ts index e11aee93..b5939bee 100644 --- a/service-worker/sw.ts +++ b/service-worker/sw.ts @@ -3,7 +3,7 @@ import { cleanupOutdatedCaches, createHandlerBoundToURL, precacheAndRoute } from 'workbox-precaching' import { NavigationRoute, registerRoute } from 'workbox-routing' import { CacheableResponsePlugin } from 'workbox-cacheable-response' -import { StaleWhileRevalidate } from 'workbox-strategies' +import { NetworkFirst, StaleWhileRevalidate } from 'workbox-strategies' import { ExpirationPlugin } from 'workbox-expiration' import { onNotificationClick, onPush } from './web-push-notifications' @@ -33,6 +33,7 @@ if (import.meta.env.DEV) // deny api and server page calls let denylist: undefined | RegExp[] if (import.meta.env.PROD) { + const pwaIcons = /^\/(pwa-.*|maskable-icon|shortcuts\/.*|screenshots\/.*)\.(png|webp)/ denylist = [ /^\/api\//, /^\/login\//, @@ -45,37 +46,28 @@ if (import.meta.env.PROD) { /^\/emojis\//, // exclude sw: if the user navigates to it, fallback to index.html /^\/sw\.js$/, - // exclude webmanifest: has its own cache, if the user navigates to it, fallback to index.html + // exclude web manifest icons + pwaIcons, + // exclude web manifest: has its own cache, if the user navigates to it, fallback to index.html /^\/manifest-(.*)\.webmanifest$/, ] -} -// only cache pages and external assets on local build + start or in production -if (import.meta.env.PROD) { - // include webmanifest cache + // only cache pages and external assets on local build + start or in production + // include webmanifest and images cache registerRoute( ({ request, sameOrigin, url }) => - sameOrigin && request.destination === 'manifest' && url.pathname.startsWith('/manifest-'), - new StaleWhileRevalidate({ + sameOrigin && (( + request.destination === 'manifest' && url.pathname.startsWith('/manifest-') + ) || ( + request.destination === 'image' && pwaIcons.test(url.pathname) + )), + new NetworkFirst({ cacheName: 'elk-webmanifest', // responses with a Vary: Accept-Encoding header matchOptions: { ignoreVary: true, }, plugins: [ - { - fetchDidFail: async ({ error, request }) => { - console.error('webmanifest fetchDidFail', error, request.url) - }, - handlerDidError: async ({ error, request }) => { - console.error('webmanifest handlerDidError', error, request.url) - return undefined - }, - cacheWillUpdate: async ({ request, response }) => { - console.error('webmanifest cacheWillUpdate', request.url) - return response?.status === 200 ? response : null - }, - }, new CacheableResponsePlugin({ statuses: [200] }), // we only need a few entries new ExpirationPlugin({ maxEntries: 100 }),