Service Worker 更新后如何硬刷新 Firefox?
How to hard refresh Firefox after Service Worker update?
我已经实现了下面的代码来清除服务工作者缓存和重新加载 - 在用户接受服务工作者的更新之后。该代码在 Chrome 和 Edge 中运行良好,但 Firefox 不会重新加载页面。 Firefox 会一直要求安装相同的版本,直到我硬刷新(shift 重新加载)页面。
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 开发工具中,我可以看到新的服务工作者 precache,但所有其他缓存都属于以前的版本。在 shift-reload 之后,新的 service worker 被“完全激活”。
如何让 Firefox 在安装新的 Service Worker 后自动硬重新加载页面?
更新: 似乎 Firefox 在 app-js
.
的第 13 行缺少服务工作者的句柄
更新:控制台输出表明浏览器之间的代码序列不同?
Chrome / 边
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
火狐
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
。
根据 this 文档:- ServiceWorkerContainer
接口的 oncontrollerchange
属性 是一个事件处理程序,每当“controllerchange 事件发生”——当文档的关联 ServiceWorkerRegistration 获得 一个新的活跃工作者。
要使用它,您可以附加一个事件处理程序,它只会在新服务工作者激活时被触发。如果您愿意,可以使用 reload
函数重新加载页面。
navigator.serviceWorker.addEventListener('controllerchange', function(){
window.location.reload();
});
我创建了一个特例,因为 Firefox 似乎以不同于 chromium 的方式安装新的 service-worker(在第 13 行没有 service-worker 注册的句柄)
当新的 service worker 正在等待时 showSkipWaitingPrompt
被触发并且
- 在 Chromium 中,service-worker 注册准备就绪 ---> 我们调用 SKIP_WAITING --> 浏览器重新加载并替换 service worker
- 在 Firefox 中,service-worker 注册句柄不可访问 还 --> 我们不能调用 SKIP_WAITING
对我来说,解决方案是在注册中添加以下行。当新的 service-worker 处于等待状态并且我们有注册句柄时,这会告诉 Firefox 跳过等待。
wb.register().then((r) => {
registration = r
if(registration.waiting){ mySkipWaitingNow() } // Fix for firefox
...
mySkipWaitingNow()
告诉 service-worker SKIP_WAITING 而不提示用户。
这永远不会在 Chrome/Edge 中触发,因为浏览器会在 showSkipWaitingPrompt()
中重新加载 - 请参阅上面的第 1 点。
为了防止可能的永恒循环,我还创建了一个全局变量 skipWaitingConfirmed
,它在 showSkipWaitingPrompt()
中设置并在 mySkipWaitingNow()
.
中签入
/K
我已经实现了下面的代码来清除服务工作者缓存和重新加载 - 在用户接受服务工作者的更新之后。该代码在 Chrome 和 Edge 中运行良好,但 Firefox 不会重新加载页面。 Firefox 会一直要求安装相同的版本,直到我硬刷新(shift 重新加载)页面。
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 开发工具中,我可以看到新的服务工作者 precache,但所有其他缓存都属于以前的版本。在 shift-reload 之后,新的 service worker 被“完全激活”。
如何让 Firefox 在安装新的 Service Worker 后自动硬重新加载页面?
更新: 似乎 Firefox 在 app-js
.
更新:控制台输出表明浏览器之间的代码序列不同?
Chrome / 边
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
火狐
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
。
根据 this 文档:- ServiceWorkerContainer
接口的 oncontrollerchange
属性 是一个事件处理程序,每当“controllerchange 事件发生”——当文档的关联 ServiceWorkerRegistration 获得 一个新的活跃工作者。
要使用它,您可以附加一个事件处理程序,它只会在新服务工作者激活时被触发。如果您愿意,可以使用 reload
函数重新加载页面。
navigator.serviceWorker.addEventListener('controllerchange', function(){
window.location.reload();
});
我创建了一个特例,因为 Firefox 似乎以不同于 chromium 的方式安装新的 service-worker(在第 13 行没有 service-worker 注册的句柄)
当新的 service worker 正在等待时 showSkipWaitingPrompt
被触发并且
- 在 Chromium 中,service-worker 注册准备就绪 ---> 我们调用 SKIP_WAITING --> 浏览器重新加载并替换 service worker
- 在 Firefox 中,service-worker 注册句柄不可访问 还 --> 我们不能调用 SKIP_WAITING
对我来说,解决方案是在注册中添加以下行。当新的 service-worker 处于等待状态并且我们有注册句柄时,这会告诉 Firefox 跳过等待。
wb.register().then((r) => {
registration = r
if(registration.waiting){ mySkipWaitingNow() } // Fix for firefox
...
mySkipWaitingNow()
告诉 service-worker SKIP_WAITING 而不提示用户。
这永远不会在 Chrome/Edge 中触发,因为浏览器会在 showSkipWaitingPrompt()
中重新加载 - 请参阅上面的第 1 点。
为了防止可能的永恒循环,我还创建了一个全局变量 skipWaitingConfirmed
,它在 showSkipWaitingPrompt()
中设置并在 mySkipWaitingNow()
.
/K