本文所讲的解决方案的使用场景为常规vue项目,由于项目功能比较复杂导致主包功能过大,页面首次加载非常缓慢,后期对业务代码进行了分包处理,项目入口文件禁用了文件缓存,html/js文件都是动态更新的。
但此后测试组很快就发现了下面的诡异的vue-router
路由跳转失灵,或者按钮无法触发click
事件等一系列诡异问题,控制台显示只是语法报错(Uncaught SyntaxError : Unexpected token <
)问题,之所以说诡异是因为,一般都会先排业务代码和第三方库有没有问题,结果是并不存在,而且也不是100%可以复现。
后来经同事跟进分析发现复现问题时与发版有关,基于此继续分析才发现是因为业务代码分包,发版之后服务端代码更新了,如果有人在发版前打开过页面,那么他就会碰到前面的问题,这主要是因为某些业务代码更新后,分包也会随之更新,而已经打开的页面使用的分包链接还是未发版的路径,出现代码块丢失所致。
找到问题的原因,基本上就算解决了问题的一半,后面我同事给出的解决方案就是在项目的/public下定义一个包含版本信息的version.json
文件:
//---- 路径:/public/version.json ----
{"code":"0","version":"10.1.41"}
然后在路由拦截中每次调用前获取一次实时的版本信息,对比上一次版本和当前版本是否一致,不一致就缓存新版本新并重载当前页面,相当于强制刷新了,这样就解决了上面的问题(个人觉得这个方案不是最优的,应该有更好的办法,不过不是本文要讲的内容)。
但这里有个麻烦的问题,就是版本号需要手动维护,显然这不符合程序员的风格,因此我就基于node.js对其做了优化,使得每次发版自动更新版本信息,这样就避免了发版时很容易遗忘改版本问题。因为是自动生成json,版本号也改成了日期时间,这样更简单明了。
优化思路是,先读取/public/version.json
文件,解析成对象,这样我们就获取到了版本信息,然后用moment.js
获取当前日期时间(这里需要注意需要npm install moment --save
安装moment
包),更新版本信息并重新写入/public/version.json
。
那么我们该在什么时候执行呢,当然是npm run build
之前啦,需要修改package.json下的script配置:
//---- 文件路径:/package.json ----
"scripts": {
"serve": "vue-cli-service serve",
"dev": "vue-cli-service serve --mode development",
"test": "vue-cli-service serve --mode test",
"prod": "vue-cli-service serve --mode prod",
"build": "node ./src/updateVersion.js && vue-cli-service build --mode prod",
},
//---- 文件路径:/src/updateVersion.js ----
const moment = require('moment');
const fs = require('fs');
// 初始化数据
const fileName = './public/version.json'
const datetime = moment().format('YYYY-MM-DD HH:mm:ss')
const defaultVersion = {code: '0', version: '1.0.0', updateTime: datetime}
// 更新版本信息
updateVersion()
// 更新版本信息
function updateVersion() {
console.log('-> 开始更新版本信息'.red, datetime);
try {
const content = fs.readFileSync(fileName, 'utf-8');
let version = JSON.parse(content)
console.log(`-> 读取 version.json 成功!`);
version.updateTime = datetime
// 更新版本信息
writeJson(version)
} catch (err) {
console.log(`-> 读取 version.json 失败!`);
// 写入默认版本信息
console.log(`-> 尝试写入默认数据!`);
writeJson(defaultVersion)
}
// 辅助提示信息
console.log('... ...');
console.log('-------> Over <-------');
}
// 写入json文件
function writeJson(version) {
try {
console.log(`-> 正在写入文件: `, fileName);
const write = fs.writeFileSync(fileName, JSON.stringify(version), {flag:'w+',encoding:'utf-8'});
console.log(`-> 写入 version.json 成功`);
} catch (err) {
console.log(`-> 写入 version.json 失败: `, err);
throw err;
}
}