Service Worker更新后如何硬刷新Firefox



我已经实现了下面的代码,以在用户接受服务工作者的更新后清除服务工作者缓存并重新加载。该代码在Chrome和Edge中运行良好,但Firefox不会重新加载页面。Firefox会一直要求安装相同的版本,直到我硬刷新(shift reload(页面。

service-worker-base.js

// Imports
const CACHE_DYNAMIC_NAME = 'DEBUG-035'
setCacheNameDetails({ prefix: 'myApp', suffix: CACHE_DYNAMIC_NAME });
// Cache then network for css
registerRoute(
'/dist/main.css',
new StaleWhileRevalidate({
cacheName: `${CACHE_DYNAMIC_NAME}-css`,
plugins: [
new ExpirationPlugin({
maxEntries: 10, // Only cache 10 requests.
maxAgeSeconds: 60 * 60 * 24 * 7 // Only cache requests for 7 days
})
]
})
)
// Cache then network for images
//...
// Use a stale-while-revalidate strategy for all other requests.
setDefaultHandler(new StaleWhileRevalidate())
precacheAndRoute(self.__WB_MANIFEST)
self.addEventListener('message', (event) => {
if (event.data && event.data.type === 'SKIP_WAITING') {
self.skipWaiting()
}
})
// Clear cache before installing new service worker
self.addEventListener('activate', (event) => {
var cachesToKeep = ['none'];
event.waitUntil(
caches.keys().then((keyList) => {
return Promise.all(keyList.map((key) => {
if (cachesToKeep.indexOf(key) === -1) {
console.log('Delete cache', key)
return caches.delete(key);
}
}));
})
);
event.waitUntil(self.clients.claim());
});
//...

app.js

const enableServiceWorker = process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'qa'
const serviceWorkerAvailable = ('serviceWorker' in navigator) ? true : false
if (enableServiceWorker && serviceWorkerAvailable) {
const wb = new Workbox('/service-worker.js');
let registration;
const showSkipWaitingPrompt = (event) => {
if (window.confirm("New version available! Refresh?")) {
wb.addEventListener('controlling', (event) => {
window.location.reload();
});
console.log('registration', registration) //<-- LINE 13 
// In Chrome and Edge this logs a service worker registration object
// In Firefox, this is undefined !!? 
if (registration && registration.waiting) {
messageSW(registration.waiting, {type: 'SKIP_WAITING'});
}
}
}
// Add an event listener to detect when the registered service worker has installed but is waiting to activate.
wb.addEventListener('waiting', showSkipWaitingPrompt);
wb.addEventListener('externalwaiting', showSkipWaitingPrompt);
wb.register().then((r) => {
registration = r
console.log('Service worker registered', registration) //<-- LINE 23
}).catch(registrationError => {
console.error('Service worker error', registrationError )
})
}
// Install prompt event handler
export let deferredPrompt
window.addEventListener('beforeinstallprompt', (event) => {
event.preventDefault() // Prevent Chrome 76 and later from showing the mini-infobar
deferredPrompt = event // Stash the event so it can be triggered later.

// Update UI notify the user they can add to home screen
try{
showInstallPromotion()
}catch(e){
// console.log('showInstallPromotion()', e)
}
})
window.addEventListener('appinstalled', (event) => {
console.log('a2hs installed')
})

在Firefox开发工具中,我可以看到新的服务工作者预缓存,但所有其他缓存都属于以前的版本。在换班重新加载之后,新的服务人员得到";"完全激活";。

如何让Firefox在安装新的服务人员后自动硬重新加载页面?

更新:Firefox似乎缺少app-js第13行的服务工作者的句柄。

UPDATE:控制台输出指示浏览器之间的代码序列不同?

Chrome/Edge

registration > ServiceWorkerRegistration {installing: null, waiting: ServiceWorker, active: ServiceWorker, navigationPreload: NavigationPreloadManager, scope: "http://127.0.0.1:8080/", …} app.js:13 
**PAGE RELOAD***
Service worker registered ServiceWorkerRegistration {installing: null, waiting: null, active: ServiceWorker, navigationPreload: NavigationPreloadManager, scope: "http://127.0.0.1:8080/", …} app.js:23

Firefox

registration undefined app.js:13:14
Service worker registered > ServiceWorkerRegistration { installing: null, waiting: ServiceWorker, active: ServiceWorker, scope: "http://127.0.0.1:8080/", updateViaCache: "imports", onupdatefound: null, pushManager: PushManager } app.js:23:12

问候/K

这可能会对您有所帮助,请检查serviceworker的controllerchange

根据本文档:-ServiceWorkerContainer接口的oncontrollerchange属性是一个事件处理程序;controllerange事件发生"——当文档的关联ServiceWorkerRegistration获取一个新的活动worker时。

要使用它,您可以附加一个事件处理程序,并且只有当新的服务工作者激活时才会触发它。如果需要,可以使用reload功能重新加载页面。

navigator.serviceWorker.addEventListener('controllerchange', function(){
window.location.reload();
});

我创建了一个特例,因为Firefox似乎安装了与chromium不同的新服务工作者(没有第13行服务工作者注册的句柄(

当新的服务工作者正在等待时,showSkipWaitingPrompt被触发并且

  1. 在Chromium中,服务人员注册已准备就绪--->我们称之为SKIP_WAITING->浏览器重新加载并替换服务工作者
  2. 在Firefox中,服务工作者注册句柄还不可访问-->我们不能调用SKIP_WAITING

对我来说,解决方案是在注册中添加以下行。当新的服务工作人员处于等待状态并且我们有一个注册句柄时,这条消息会告诉Firefox跳过等待。

wb.register().then((r) => {
registration = r
if(registration.waiting){ mySkipWaitingNow() } // Fix for firefox
...

mySkipWaitingNow()在不提示用户的情况下告诉服务工作人员跳过_等待。

这在Chrome/Edge中永远不会触发,因为浏览器在showSkipWaitingPrompt()中重新加载-请参阅上面的第1点。

为了防止可能的永恒循环,我还创建了一个全局变量skipWaitingConfirmed,该变量在showSkipWaitingPrompt()中设置并在mySkipWaitingNow()中检查。

/K

最新更新