Я реализовал Workbox для генерации моего сервисного работника с помощью веб-пакета. Это работает - я могу подтвердить, что ревизия обновлена в сгенерированном сервисном работнике при запуске "generate-sw": "workbox inject:manifest"
.
Проблема в том, что я заметил, что мои клиенты не обновляют кэш после нового выпуска. Даже через несколько дней после обновления работника сервиса мои клиенты все еще кэшируют старый код, а новый код загружается только после нескольких обновлений и / или отмены регистрации работника сервиса. Для каждого выпуска я подтверждаю, что ревизия обновляется.
Я понимаю, что мне нужно реализовать skipWaiting
, чтобы гарантировать обновление клиентов - особенно PWA. Я прочитал и попытался следовать третьему подходу здесь: https://redfin.engineering/how-to-fix-the-refresh-button-when-using-service-workers-a8e27af6df68.
Мое приложение монтируется в app.js
Я добавил этот код в serviceWorker-base.js
addEventListener('message', function(messageEvent){
if (messageEvent.data === 'skipWaiting') return skipWaiting();
});
У меня есть этот код в app.js
const runServiceWorker = true
const serviceWorkerAvailable = ('serviceWorker' in navigator) ? true : false
// reload once when the new Service Worker starts activating
let refreshing
navigator.serviceWorker.addEventListener('controllerchange', function() {
if (refreshing) return
refreshing = true
window.location.reload()
}
)
function promptUserToRefresh(reg) {
// this is just an example - don't use window.confirm in real life; it's terrible
if (window.confirm("New version available! OK to refresh?")) {
reg.waiting.postMessage('skipWaiting')
}
}
function listenForWaitingServiceWorker(reg, callback) {
console.log('listenForWaitingServiceWorker')
function awaitStateChange() {
reg.installing.addEventListener('statechange', function() {
if (this.state === 'installed') callback(reg)
})
}
if (!reg) return
if (reg.waiting) return callback(reg)
if (reg.installing) awaitStateChange()
reg.addEventListener('updatefound', awaitStateChange)
}
// Register service worker
if (runServiceWorker && serviceWorkerAvailable) {
navigator.serviceWorker.register('/serviceWorker.js')
.then( (registration) => {
console.log('Service worker registered', registration)
listenForWaitingServiceWorker(registration, promptUserToRefresh) // <-- Added to existing code
})
}else{
console.log('Service worker disabled - process.env.NODE_ENV', process.env.NODE_ENV)
}
Проблема с этим кодом в том, что promptUserToRefresh()
вызывается только при начальной установке работника сервиса, а не при новой обслуживающий работник ждет!
Кроме того, я получаю приведенную ниже ошибку при принятии первой установки.
TypeError: registration.waiting is null
promptUserToRefresh app.js:154
awaitStateChange app.js:162
Ошибка вызывается в promptUserToRefresh(registration)
по registration.waiting.postMessage('skipWaiting')
Я также проверил этот подход с тем же результатом: https://github.com/GoogleChrome/workbox/issues/1120