Estoy usando Workbox y BroadcastUpdatePlugin() en mi serviceWorker para solicitar al usuario que actualice la página cuando se actualice un archivo en caché. Funciona muy bien cuando solo hay un archivo actualizado, pero cuando publico varias actualizaciones a la vez (archivos HTML, CSS y JS), se solicita al usuario que actualice la página para cada archivo.
¿Cómo puedo actualizar todos los archivos en el caché y luego solicitar al usuario que actualice la página solo una vez, cuando el detector de eventos haya dejado de recibir mensajes de actualización?
Código de ServiceWorker
const {BroadcastUpdatePlugin} = workbox.broadcastUpdate; registerRoute( ({request}) => request.destination === 'document', new StaleWhileRevalidate({ //new NetworkOnly({ cacheName: 'pages', plugins: [ new BroadcastUpdatePlugin(), ], }) ) registerRoute( ({request}) => request.destination === 'script' || request.destination === 'style', new StaleWhileRevalidate({ //new NetworkOnly({ cacheName: 'assets', plugins: [ new BroadcastUpdatePlugin(), ], }) )código JavaScript
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('sw.js', { scope: '/' }).then(swReg => { console.log('Service Worker Registered', swReg); }).catch(error => { console.log('There was an error!', error); }) }) // Listen for cache updates and prompt a page reload navigator.serviceWorker.addEventListener('message', async (event) => { if (event.data.meta === 'workbox-broadcast-update') { const {cacheName, updatedURL} = event.data.payload; const cache = await caches.open(cacheName); const updatedResponse = await cache.match(updatedURL); const updatedText = await updatedResponse.text(); console.log('Updated: '+cacheName+', '+updatedURL); // prompts for every update if(confirm('Content Updated. Please refresh the page.')){ window.location.reload; } } }) }Podría imaginar que podría haber una lógica en su trabajador de servicio que podría ayudar con esto, por ejemplo, mirando el cliendId en FetchEvent que desencadenó una actualización y solo enviando el mensaje condicionalmente si no ha visto ese clientId antes.
Pero eso requeriría un montón de lógica personalizada más allá de lo que ya proporciona BroadcastUpdatePlugin , y podría ser propenso a errores: si su trabajador de servicio transmite una actualización, entonces el usuario actúa sobre la actualización, y luego hay otra actualización que podría transmitirse, probablemente quiere darle al usuario otra oportunidad de actuar en consecuencia, pero sería difícil para el trabajador del servicio saber si transmitir un mensaje al mismo clientId de cliente en ese escenario.
Un enfoque más limpio sería mover la lógica que impedía varias solicitudes al código del cliente de la window .
Hay un par de formas de ir allí, pero lo que me parece más limpio se basaría en la resolución de una promesa para activar el mensaje. Puede llamar a la función de resolve de una promesa varias veces, pero el then() en la cadena de la promesa solo se invocará una vez, lo que le dará el comportamiento que está buscando.
if ('serviceWorker' in navigator) { window.addEventListener('load', () => { navigator.serviceWorker.register('/sw.js'); }); const waitForUpdate = new Promise((resolve) => { navigator.serviceWorker.addEventListener('message', async (event) => { if (event.data.meta === 'workbox-broadcast-update') { const {cacheName, updatedURL} = event.data.payload; const cache = await caches.open(cacheName); const updatedResponse = await cache.match(updatedURL); const updatedText = await updatedResponse.text(); console.log(`Updated ${updatedURL} in ${cacheName}: ${updatedText}`); // Calling resolve() will trigger the promise's then() once. resolve(); } }); }); waitForUpdate.then(() => { if (confirm('Content updated. Please refresh the page.')) { window.location.reload(); } }); }(También puede usar un enfoque que dependa de una variable global o algo similar que se voltee la primera vez que muestre el aviso y cortocircuite la visualización del aviso cada vez que lo haga, pero me gusta usar promesas para este tipo de cosas).