你可能在浏览器见到过下面这种UI,这是在vue我的项目从新build在服务端部署后,浏览器刷新页面弹出的提醒,这时如果用户点击更新就会重载页面,革除之前的缓存获取最新内容。
这是怎么产生的呢?你可能会想到上面的形式:
- 服务端编译重新部署保护一个版本号,客户端通过轮询检测和本地存储的是否雷同,发现更新的版本就弹框提醒(毛病 耗电。尤其是在挪动端)
- 通过在html中做版本标记...
- websocket长连贯像客户端推送版本更新(繁琐)
- service worker
通过观察截图左下角的红框,能够看出这个网站采纳形式是 注册了 service worker。
当刷新页面后之前注册的 service worker 的 updated(){} 生命周期中监听到有新的内容可供更新,触发更新弹框,提醒用户更新。
这种形式只需前端解决,不须要服务端做任何工作。只有每次build后从新在服务端部署,有文件产生变动,就能够被service worker发现。
这篇文章就来记录一下怎么做。
引入cli-plugin-pwa
参考 vue我的项目引入pwa使网页利用可装置
在下面的根底上,向下进行。
在registerServiceWorker.js增加事件触发
/* eslint-disable no-console */import { register } from 'register-service-worker'if (process.env.NODE_ENV === 'production') { 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.') document.dispatchEvent( new CustomEvent('swUpdated', { detail: registration }) ) }, offline () { console.log('No internet connection found. App is running in offline mode.') }, error (error) { console.error('Error during service worker registration:', error) } })}
在updated() {} 中增加swUpdated自定义事件,而后在ReloadPrompt.vue组件中监听事件,有更新时弹出 提醒用户更新。
这个组件须要在App.vue中引入,或者其余适合的中央。
<!-- ReloadPrompt.vue --><template> <div> <!-- <el-button @click="handlePrompt(true)">show</el-button> --> <transition name="el-zoom-in-bottom"> <el-card class="fix_right_bottom" v-if="visible"> <div style="padding: 14px;"> <span style="font-size: 14px;"> 发现新版本,点击"更新"获取。 </span> <div class="button_group"> <el-button size="mini" @click="handlePrompt(false)">敞开</el-button> <el-button type="primary" size="mini" @click="refreshApp">更新</el-button> </div> </div> </el-card> </transition> </div></template><script>export default { created() { document.addEventListener('swUpdated', this.updateAvailable, { once: true }) navigator.serviceWorker.addEventListener('controllerchange', () => { // We'll also need to add 'refreshing' to our data originally set to false. if (this.refreshing) return this.refreshing = true // Here the actual reload of the page occurs window.location.reload() }) }, data() { return { visible: false, registration: null, refreshing: false } }, methods: { handlePrompt(val) { this.visible = val }, updateAvailable(event) { this.registration = event.detail this.visible = true }, refreshApp() { this.visible = false // Make sure we only send a 'skip waiting' message if the SW is waiting if (!this.registration || !this.registration.waiting) return // Send message to SW to skip the waiting and activate the new SW this.registration.waiting.postMessage({ type: 'SKIP_WAITING' }) } }}</script><style scoped>.fix_right_bottom { position: fixed; right: 20px; bottom: 20px;}.button_group { margin-top: 10px;}</style>
// service-worker.js// install new service worker when ok, then reload page.self.addEventListener("message", msg => { if (msg.data && msg.data.type === 'SKIP_WAITING'){ self.skipWaiting() }})
从新来看一下这个流程,上一版的网页注册了service-worker.js,服务端从新build部署,有新内容呈现,=> 客户端刷新 => 发现有新的service-worker能够装置 => 触发updated(){} => ReloadPrompt.vue => 触发一次 "swUpdated" => 弹出更新弹框用户点击更新 => 向service-worker.js 传递 "SKIP_WAITING" => 新的service-worker.js装置后 => 触发ReloadPrompt.vue 中的 "controllerchange" 实现页面重载。
这样就解决了spa利用让人头疼的缓存问题。