diff --git a/packages/docs/src/plugins/pwa.ts b/packages/docs/src/plugins/pwa.ts index ee810e0097f..0c301c25e98 100644 --- a/packages/docs/src/plugins/pwa.ts +++ b/packages/docs/src/plugins/pwa.ts @@ -12,7 +12,12 @@ export const usePwa: PwaPlugin = async ({ isClient, router }) => { const pwa = usePwaStore() const user = useUserStore() const updateSW = pwa.updateSW = registerSW({ - onNeedRefresh () { + async onNeedRefresh () { + const registration = await navigator.serviceWorker.getRegistration() + if (registration?.active && registration?.waiting) { + await messageSW(registration.active, { type: 'CLEAN_CACHE' }) + } + if (user.pwaRefresh) pwa.snackbar = true }, }) @@ -23,3 +28,13 @@ export const usePwa: PwaPlugin = async ({ isClient, router }) => { } }) } + +function messageSW (sw: ServiceWorker, data: {}): Promise { + return new Promise(resolve => { + const messageChannel = new MessageChannel() + messageChannel.port1.onmessage = (event: MessageEvent) => { + resolve(event.data) + } + sw.postMessage(data, [messageChannel.port2]) + }) +} diff --git a/packages/docs/src/service-worker.js b/packages/docs/src/service-worker.js index 1ba1fd6f1d1..3ec4c96b4d2 100644 --- a/packages/docs/src/service-worker.js +++ b/packages/docs/src/service-worker.js @@ -3,16 +3,9 @@ import { matchPrecache, precacheAndRoute } from 'workbox-precaching' import { registerRoute, setCatchHandler, setDefaultHandler } from 'workbox-routing' import { CacheFirst, NetworkOnly } from 'workbox-strategies' -self.addEventListener('install', event => { - event.waitUntil((async () => { - return Promise.all( - (await caches.keys()) - .filter(k => k.includes(self.registration.scope) && (k.includes('-precache-') || k.includes('-runtime-'))) - .map(name => caches.delete(name)) - ) - })()) -}) -precacheAndRoute(self.__WB_MANIFEST) +const MANIFEST = self.__WB_MANIFEST + +precacheAndRoute(MANIFEST) const cacheFirst = new CacheFirst() const networkOnly = new NetworkOnly() @@ -48,11 +41,50 @@ setCatchHandler(async ({ url, request }) => { return Response.error() }) -self.addEventListener('message', event => { - if (event.data?.type === 'SKIP_WAITING') self.skipWaiting() - else console.log(event) +self.addEventListener('message', async event => { + if (event.data?.type === 'SKIP_WAITING') { + console.log('[SW] Skip waiting') + self.skipWaiting() + } else if (event.data?.type === 'CLEAN_CACHE') { + const precache = await openCache('precache') + + const responses = await Promise.all( + MANIFEST.map(entry => precache.match(entry.url + (entry.revision ? `?__WB_REVISION__=${entry.revision}` : ''))) + ) + + // Date of earliest entry in the old manifest + const date = Array.from( + new Set(responses.map(getDate)) + ).sort()[0] + + let n = 0 + for (const cache of [precache, await openCache('runtime')]) { + for (const req of await cache.keys()) { + const res = await cache.match(req) + if (res && getDate(res) < date) { + ++n + await cache.delete(req) + } + } + } + console.log(`[SW] Cleared ${n} old items from cache`) + } else console.log(event) }) function getFallbackDocument (url) { return matchPrecache(url.pathname.startsWith('/eo-UY/') ? '_crowdin.html' : '/_fallback.html') } + +async function openCache (name) { + const precache = (await caches.keys()).find(k => k.includes(self.registration.scope) && k.includes(`-${name}-`)) + + if (!precache) return + + return caches.open(precache) +} + +function getDate (response) { + const date = new Date(Object.fromEntries(response.headers).date) + date.setMinutes(0, 0, 0) + return date.getTime() +} diff --git a/packages/docs/src/shims.d.ts b/packages/docs/src/shims.d.ts index 818410ac7f1..303758db357 100644 --- a/packages/docs/src/shims.d.ts +++ b/packages/docs/src/shims.d.ts @@ -55,10 +55,6 @@ declare module 'cosmicjs' { export default function Cosmic (): Cosmic } -declare module 'virtual:pwa-register' { - export function registerSW (params: { immediate?: boolean }): void -} - declare module 'virtual:examples' { import type { Component } from 'vue'