前言
用户在访问单页面网站时,如果生产环境已经发布了新的版本(有功能上的变化),由于单页面中路由特性或浏览器缓存的原因,并不会重新加载前端资源,此时用户浏览器所并非加载是最新的代码,从而可能遇到一些 bug。
那么,在我们部署之后,如何提醒用户版本更新,并引导用户刷新页面呢?
解决方案
这里用的【轮询】的方式请求index.html
文件,从中解析里面的js
文件,由于vue打包后每个js
文件都有指纹标识
,因此对比每次打包后的指纹,分析文件是否存在变动,如果有变动则提示用户更新!
环境:vue3 + ts + vite + element-plus
步骤
1.在utils
文件夹下新建auto-update.ts
,内容如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| import { ElMessageBox } from 'element-plus'
let lastSrcs: any; let needTip = true;
const scriptReg = /<script.*src=["'](?<src>[^"']+)/gm;
const extractNewScripts = async () => { const html = await fetch('/?_timestamp=' + Date.now()).then((resp) => resp.text()); scriptReg.lastIndex = 0; let result = []; let match: RegExpExecArray while ((match = scriptReg.exec(html) as RegExpExecArray)) { result.push(match.groups?.src) } return result; }
const needUpdate = async () => { const newScripts = await extractNewScripts(); if (!lastSrcs) { lastSrcs = newScripts; return false; } let result = false; if (lastSrcs.length !== newScripts.length) { result = true; } for (let i = 0; i < lastSrcs.length; i++) { if (lastSrcs[i] !== newScripts[i]) { result = true; break } } lastSrcs = newScripts; return result; } const DURATION = 10000;
export const autoRefresh = () => { setTimeout(async () => { const willUpdate = await needUpdate(); if (willUpdate) { setTimeout(() => { ElMessageBox.confirm('检测到页面有内容更新,为了功能的正常使用,是否立即刷新?', '更新提示', { confirmButtonText: '确认', showCancelButton: false, type: 'warning' }).then(() => { location.reload(); }) }, 30000); needTip = false; } if (needTip) { autoRefresh(); } }, DURATION) }
|
2.关于vite
的相关配置,这里只放出rollupOptions
相关代码,更多详情请看 build-rollupoptions、Configuration Options
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
export default xxx = () => { return { base: './', resolve: { ... }, server: { ... }, build: { rollupOptions: { output: { chunkFileNames: 'js/[hash].js', entryFileNames: 'js/[hash].js', assetFileNames: '[ext]/[hash].[ext]', } } } } }
|
3.在入口文件mati.ts
中引入autoRefresh
,如果是生产环境,则执行autoRefresh
方法。
1 2 3 4
| import { autoRefresh } from "@/utils/auto-update" if (import.meta.env.MODE == 'production') { autoRefresh() }
|
效果
结语
如果你有更好的方案,记得在评论去留言喔~