Vite + Vue3 实现版本更新检查,实现页面自动刷新
前端版本更新检查,实现页面自动刷新。使用vite对项目进行打包,对 js 和 css 文件使用了 chunkhash 进行了文件缓存控制,但是项目的index.html文件在版本频繁迭代更新时,会存在被浏览器缓存的情况。在发版后,如果用户不强制刷新页面,浏览器会使用旧的index.html文件,在跳转页面时会向服务器端请求了上个版本 chunkhash 的 js 和 css 文件,但此时的文件已经
前端版本更新检查,实现页面自动刷新
使用 Vite 对 Vue 项目进行打包,对 js 和 css 文件使用了 chunkhash 进行了文件缓存控制,但是项目的 index.html
文件在版本频繁迭代更新时,会存在被浏览器缓存的情况。
在发版后,如果用户不强制刷新页面,浏览器会使用旧的 index.html
文件,在跳转页面时会向服务器端请求了上个版本 chunkhash 的 js 和 css 文件,但此时的文件已经在版本更新时已替换删除了,最终表现为页面卡顿,控制台报错 404。
解决思路
思路 1
服务器端发版时,上一个版本的 assets 内的文件不删除。
缺点是会随着频繁发版,服务器端前端项目文件会越来越多,浪费空间;若旧页面的接口涉及到参数改动等,会引起报错;流水线使用 docker 打包部署会变得非常麻烦。
思路 2
在每次打包生产代码时,在 public
目录下生成一个 version.json
版本信息文件,页面跳转时请求服务器端的 version.json
中的版本号和浏览器本地缓存的版本号进行对比,从而监控版本迭代更新,实现页面自动更新,获取新的 index.html
文件(前提是服务器端对 index.html
和 version.json
不缓存)。
-
首先应该禁止浏览器缓存
index.html
和version.json
,这里是 nginx 的不缓存处理的例子添加 nginx 配置
location ~ .*\.(htm|html|json)?$ { expires -1; }
-
编写 Vite 插件实现打包时自动生成版本信息
版本信息插件
TypeScript 版本,新建文件
src/plugins/versionUpdatePlugin.ts
// versionUpdatePlugin.ts import fs from "node:fs" import path from "node:path" import type { ResolvedConfig } from "vite" function writeVersion(versionFile: string, content: string) { // 写入文件 fs.writeFile(versionFile, content, (err) => { if (err) throw err }) } export default (version: string | number) => { let config: ResolvedConfig return { name: "version-update", configResolved(resolvedConfig: ResolvedConfig) { // 存储最终解析的配置 config = resolvedConfig }, buildStart() { // 生成版本信息文件路径 const file = config.publicDir + path.sep + "version.json" // 这里使用编译时间作为版本信息 const content = JSON.stringify({ version }) if (fs.existsSync(config.publicDir)) { writeVersion(file, content) } else { fs.mkdir(config.publicDir, (err) => { if (err) throw err writeVersion(file, content) }) } }, } }
JavaScript 版本,新建文件
src/plugins/versionUpdatePlugin.js
// versionUpdatePlugin.js const fs = require("fs") const path = require("path") const writeVersion = (versionFile, content) => { // 写入文件 fs.writeFile(versionFile, content, (err) => { if (err) throw err }) } export default (options) => { let config return { name: "version-update", configResolved(resolvedConfig) { // 存储最终解析的配置 config = resolvedConfig }, buildStart() { // 生成版本信息文件路径 const file = config.publicDir + path.sep + "version.json" // 这里使用编译时间作为版本信息 const content = JSON.stringify({ version: options.version }) if (fs.existsSync(config.publicDir)) { writeVersion(file, content) } else { fs.mkdir(config.publicDir, (err) => { if (err) throw err writeVersion(file, content) }) } }, } }
vite 配置文件
对于使用 TypeScript 的开发者来说,请确保在
env.d.ts
或vite-env.d.ts
文件中添加类型声明,以获得类型检查以及代码提示。// vite-env.d.ts declare const __APP_VERSION__: string
// vite.config.js or vite.config.ts export default defineConfig((config) => { const now = new Date().getTime() return { // ... define: { // 定义全局变量 __APP_VERSION__: now, }, plugins: [ // ... versionUpdatePlugin({ version: now, }), ], // ... } })
-
路由跳转时,实时检测版本
检测到新版本自动刷新页面,应该使用前置守卫,在跳转失败报错前检测,跳转失败不会触发后置守卫
const router = useRouter() // 这里在路由全局前置守卫中检查版本 router.beforeEach(async () => { await versionCheck() }) // 版本监控 const versionCheck = async () => { if (import.meta.env.MODE === "development") return const response = await axios.get("version.json") if (__APP_VERSION__ !== response.data.version) { ElMessage({ message: "发现新内容,自动更新中...", type: "success", showClose: true, duration: 1500, onClose: () => { window.location.reload() }, }) } }
更多推荐
所有评论(0)