vue PWA serviceWorker 有新内容时,如何自动刷新内容
一、问题描述
vue 自带的 pwa 插件可以很方便管理 serviceWorker 的使用,但会有一个问题。
ServiceWorker 的运行机制是这样的:
- 后台检测到新版本
- 新版 ServiceWorker 下载并安装
- 安装完成之后等待生效,只有当用户关系所有相关窗口并重新打开,新的 ServiceWorker 才会接管
而我需要在检测到新版本的内容之后自动刷新页面载入新内容。
就需要在检测到新版本安装成功之后,刷新所有实例窗口。这个操作包含两个操作:
- ServiceWorker 方面在安装成功后,向外
postMessage
信息,告诉其它窗口已经准备好更新了,skipWaiting
- 其它窗口在打开的时候就监听
postMessage
信息,当监听到指定的信息的时候,刷新自己。
具体 ServiceWorker 的响应机制可以看这篇文章,很的很详细
Handling Service Worker updates -- how to keep the app updated and stay sane
二、探索解决办法
使用 register-service-worker
,项目中 registerServiceWorker.js
的内容是这样的
js
/* eslint-disable no-console */
import { register } from 'register-service-worker'
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.\n' +
'For more details, visit https://goo.gl/AFskqB'
)
},
registered () {
console.log('Service worker has been registered.')
},
cached () {
console.log('Content has been cached for offline use.')
},
updatefound () {
console.log('New content is downloading.')
},
updated (registration) {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error(error) {
console.error('Error during service worker registration:', error)
}
})
需要做的就是在 updated 方法中发出一个内容为 SKIP_WAITING
的事件。
我第一次发的时候只发了一个字符串,结果不行。
后认真查看了最终生成的 dist/service-worker.js
的代码,并在其中加入了代码查看它获取到的 data 是什么内容
js
define(["./workbox-d6430d1c"], (function (e) {
"use strict";
e.setCacheNameDetails({prefix: "iphone"}), self.addEventListener("message", (e => {
e.data && "SKIP_WAITING" === e.data.type && self.skipWaiting()
})), e.precacheAndRoute([{
结果出来是这个结果,所以就知道 postMessage
的内容格式肯定是错了。改成下面这样就好了
js
updated (registration) {
if (registration.waiting) {
registration.waiting.postMessage({
type: 'SKIP_WAITING'
})
}
console.log('新的 ServiceWorker.js 已经下载并安装')
},