背景:
前端开发在开发过程应该会中经常碰到:修复代码bug后,打包上线,测试人员需要手动清理浏览器缓存才能看到最新的改动,比较繁琐,而且正式上线后也不可能每次代码部署后都要提醒用户去清除浏览器缓存。
实现思路:
缓存产生的主要原因是因为打包后的js文件采用默认的打包机制,只是文件增加hash值,在某种情况下会存在hash值不变导致的缓存。针对此原因入手,可以给打包后的文件增加最新标识的后缀,这里使用时间戳,此外,前端维护一个记录版本号的文件,在用户操作项目的过程中,进行新老版本号的比对,版本号更改时对浏览器缓存进行reload(这样就无需用户手动刷新浏览器缓存),即可保持项目获取最新代码。
核心代码:
项目目录public下新建version文件
vue.config.js文件中新增以下代码,每次打包时将当前时间戳写入version,并在js文件后增加时间戳。
//vue.config.js
const path = require('path')
const fs = require("fs");
// 文件路径
const filePath = path.join(__dirname, './public/version');
// 读取文件内容
fs.readFile(filePath, 'utf8', (err, data) => {
if (err) {
return;
}
let newData = String(new Date().getTime());
// 写入新内容到文件
fs.writeFile(filePath, newData, 'utf8', (writeErr) => {
if (writeErr) {
console.error(writeErr);
return;
}
console.log('File has been modified!');
});
});
module.exports = {
// 省略基础配置
......,
configureWebpack: config => {
// 省略基础配置
......,
output:{
filename:`static/js/[name].[contenthash].js?t=${new Date().getTime()}`,
chunkFilename:`static/js/[name].[contenthash].js?t=${new Date().getTime()}`
}
}
}
自定义isNewVersion方法,用于线上环境比较新老版本号 (老版本号存储在localStorage中,新版本号请求version文件获取)
// utils/systemUpdate.js
const isNewVersion = () => {
if (window.location.host.indexOf("localhost") > -1) {
// 如果是本地环境,无需对比
} else {
// 线上环境的version文件请求地址
let url = "";
url = `//${
window.location.host
}/version?t=${new Date().getTime()}`;
axios.get(url).then(res => {
console.log(" ~ file: systemUpdate.js:6 ~ axios.get ~ res", res);
if (res.status == 200) {
// 获取version文件最新版本号
let vueVersion = res.data;
// 浏览器缓存中获取之前的版本号
let localVueVersion = window.localStorage.getItem("appVersion");
if (localVueVersion && localVueVersion != vueVersion) {
// 版本号不一致,存储新版本号,并刷新浏览器缓存
window.localStorage.setItem("appVersion", vueVersion);
window.location.reload();
return;
} else {
window.localStorage.setItem("appVersion", vueVersion);
}
}
});
}
};
export default {
isNewVersion
};
在全局路由导航守卫中使用上述方法,这样可以在用户每次切换路由时对比版本号,判断是否需要刷新缓存(如果不想触发过于频繁,可以采取别的方式,比如使用定时任务等)。
// src/router/index.js (有些项目全局路由导航守卫会放在其他文件)
import { isNewVersion } from '@/utils/systemUpdate'
const router = [
// 路由配置
...
]
// 路由导航守卫
router.beforeEach((to, from, next) => {
isNewVersion()
.......
}