Service Worker - 使用 skipWaiting() 在新版本上更新缓存
Service worker - update cache on new version using skipWaiting()
我已经实现了 Workbox 以使用 webpack 生成我的 service worker。这有效 - 我可以确认在 运行 "generate-sw": "workbox inject:manifest"
.
时生成的服务工作者中的修订已更新
问题是 - 我注意到我的客户在新版本发布后没有更新缓存。即使在更新 service worker 几天后,我的客户仍在缓存旧代码,新代码只会在几次刷新后加载 and/or 注销 service worker。对于每个版本,我都确认修订已更新。
我知道我需要实施 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
代码只需重新排列后即可运行!
已更新app.js
// *** PWA Functionality START ***
// skipWaiting() functions
function promptUserToRefresh(registration) {
// this is just an example - don't use window.confirm in real life; it's terrible
if (window.confirm("New version available! Refresh?")) {
registration.waiting.postMessage('skipWaiting')
}
}
function listenForWaitingServiceWorker(registration) {
console.log('listenForWaitingServiceWorker', registration)
function awaitStateChange() {
registration.installing.addEventListener('statechange', function() {
if (this.state === 'installed') promptUserToRefresh(registration)
})
}
if (!registration) return
if (registration.waiting) return promptUserToRefresh(registration)
if (registration.installing) awaitStateChange()
registration.addEventListener('updatefound', awaitStateChange)
}
//**
const enableServiceWorker = true
const serviceWorkerAvailable = ('serviceWorker' in navigator) ? true : false
// Register service worker
if (enableServiceWorker && serviceWorkerAvailable) {
navigator.serviceWorker.register('/serviceWorker.js')
.then( (registration) => {
console.log('Service worker registered', registration)
listenForWaitingServiceWorker(registration) // ** skipWaiting() code
})
}else{
console.log('Service worker disabled - process.env.NODE_ENV', process.env.NODE_ENV)
}
// Install prompt event handler
export let deferredPrompt
window.addEventListener('beforeinstallprompt', (event) => {
// Prevent Chrome 76 and later from showing the mini-infobar
event.preventDefault()
deferredPrompt = event // Stash the event so it can be triggered later.
try{
showInstallPromotion()
}catch(e){
console.error('showInstallPromotion()', e)
}
})
window.addEventListener('appinstalled', (event) => {
console.log('a2hs installed')
})
// *** PWA Functionality END *
也许下面(删除的)行造成了所有的麻烦?
// reload once when the new Service Worker starts activating
let refreshing
navigator.serviceWorker.addEventListener('controllerchange', function() {
if (refreshing) return
refreshing = true
window.location.reload()
}
)
现在剩下的就是弄清楚如何不在首次访问应用程序/安装时显示提示! (^__^)/
我已经实现了 Workbox 以使用 webpack 生成我的 service worker。这有效 - 我可以确认在 运行 "generate-sw": "workbox inject:manifest"
.
问题是 - 我注意到我的客户在新版本发布后没有更新缓存。即使在更新 service worker 几天后,我的客户仍在缓存旧代码,新代码只会在几次刷新后加载 and/or 注销 service worker。对于每个版本,我都确认修订已更新。
我知道我需要实施 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
代码只需重新排列后即可运行!
已更新app.js
// *** PWA Functionality START ***
// skipWaiting() functions
function promptUserToRefresh(registration) {
// this is just an example - don't use window.confirm in real life; it's terrible
if (window.confirm("New version available! Refresh?")) {
registration.waiting.postMessage('skipWaiting')
}
}
function listenForWaitingServiceWorker(registration) {
console.log('listenForWaitingServiceWorker', registration)
function awaitStateChange() {
registration.installing.addEventListener('statechange', function() {
if (this.state === 'installed') promptUserToRefresh(registration)
})
}
if (!registration) return
if (registration.waiting) return promptUserToRefresh(registration)
if (registration.installing) awaitStateChange()
registration.addEventListener('updatefound', awaitStateChange)
}
//**
const enableServiceWorker = true
const serviceWorkerAvailable = ('serviceWorker' in navigator) ? true : false
// Register service worker
if (enableServiceWorker && serviceWorkerAvailable) {
navigator.serviceWorker.register('/serviceWorker.js')
.then( (registration) => {
console.log('Service worker registered', registration)
listenForWaitingServiceWorker(registration) // ** skipWaiting() code
})
}else{
console.log('Service worker disabled - process.env.NODE_ENV', process.env.NODE_ENV)
}
// Install prompt event handler
export let deferredPrompt
window.addEventListener('beforeinstallprompt', (event) => {
// Prevent Chrome 76 and later from showing the mini-infobar
event.preventDefault()
deferredPrompt = event // Stash the event so it can be triggered later.
try{
showInstallPromotion()
}catch(e){
console.error('showInstallPromotion()', e)
}
})
window.addEventListener('appinstalled', (event) => {
console.log('a2hs installed')
})
// *** PWA Functionality END *
也许下面(删除的)行造成了所有的麻烦?
// reload once when the new Service Worker starts activating
let refreshing
navigator.serviceWorker.addEventListener('controllerchange', function() {
if (refreshing) return
refreshing = true
window.location.reload()
}
)
现在剩下的就是弄清楚如何不在首次访问应用程序/安装时显示提示! (^__^)/