前端版本更新技术方案
背景
公司的移动端和PC端,分别是angular和vue库开发的项目,每次在打包发布新版本后,用户都需要手动刷新页面获取最新代码或样式,否则发布的最新的js\css\image等资源文件得不到更新,为解决此问题对两个项目做了以下改造;
技术方案说明
项目在打包时利用插件生成一个时间戳作为版本信息,打入到一个json文件里
前端路由拦截器里监听到路由变化时,请求这个json文件,和本地的localStorage里的版本信息做对比:
如果本地没有缓存:直接做自动刷新浏览器处理,同时把json文件里的版本信息存到缓存里
如果本地有缓存:对比是否有差异,无差异不做处理;有差异则调用浏览器的location.reload()做自动刷新处理,同时将服务器的版本信息存到localStorage里,再有路由变化时则不会再次刷新了,直到下次新版本发布重新走步骤2
代码实现
PC端
首先编写一个webpack plugin :VersionFilePlugin.js,主要逻辑为生成一个version.json在项目打包配置output.path的static文件夹下
const fs = require('fs');
const path = require('path');
/**
* 生成版本信息
*/
class VersionFilePlugin {
constructor(options) {
this.options = options || {};
}
apply(compiler) {
compiler.plugin('done', (stat) => {
//方案:作为json文件打到dist里,然后通过网络请求进行查找version.json文件
const version = Date.now(); // 获取当前时间戳
const versionData = { version };
const versionFilePath = path.join(compiler.options.output.path, 'static/version.json');
// 写入version.json文件
fs.writeFileSync(versionFilePath, JSON.stringify(versionData));
});
}
}
module.exports = VersionFilePlugin;
在webpack.prod.conf里引入这个插件(uat和prod的打包都是使用的这个文件,开发环境的webpack.dev.conf不需要引入此插件功能)
const VersionFilePlugin = require('../plugins/VersionFilePlugin');
plugins:[
...省略其他代码
new VersionFilePlugin() 在所有plugin的最后引入这个VersionFilePlugin
]
到此步为止,运行pc的npm run build:shuat 或者 npm run build:shprod可以看到打包出的dist文件夹下已有一个version.json文件了
接下来在api里请求这个json文件,/api/version.js
import request from '../utils/request';
//获取版本信息
export function getVersion() {
return request.MainService({
url: '/pc/static/version.json',
method: 'get',
});
}
在app.vue里的全局监听路由变化进行调用上面的api
watch: {
$route(val, old) {
//获取版本信息
getVersion().then(data => {
if(data && data.version){
versionExamine(data.version);
}
})
}
}
versionExamine方法是util里的工具方法,用于对比本地缓存里的versionData,此工具方法移动和pc可以共用
//版本检查:根据本地缓存的版本信息和服务器的版本信息进行对比
export function versionExamine(timestamp){
let storage_version = localStorage.getItem('versionData');
if(storage_version){//本地有版本信息则进行对比
if(Number(timestamp) !== Number(storage_version)){
localStorage.setItem('versionData',timestamp);
console.log('强制刷新页面~~');
location.reload();
}
}else{//没有的话先存下版本信息,再进行刷新页面
localStorage.setItem('versionData',timestamp);
console.log('强制刷新页面~~');
location.reload();
}
}
最后,如有版本更新,在pc的页面进行路由跳转时会自动进行刷新浏览器的当前tab页,同时可看到【强制刷新页面~~】的log
移动端
由于移动端的的angular项目很老,是angular5的版本(目前官方已更新16),直接使用PC的同一个webpack插件的方式不适用于这个版本,所以做了以下修改:
这个生成version.json的插件不再是一个webpack形式,而是直接使用node里的fs模块生成一个文件出来,在执行打包时把它当做一个命令顺序执行:
version-plugin.js
const fs= require('fs');
const version = Date.now(); // 获取当前时间戳
const versionData = { version };
// 写入version.json文件
console.log('versionData', versionData);
fs.writeFileSync('./dist/assets/version.json', JSON.stringify(versionData));
现在package.json里增加一个命令,然后修改uat的打包命令:
"version-plugin": "node ./version-plugin.js",
uat修改前的打包命令:
"produat": "npm run git-plugin --max_old_space_size=16384 && node --max_old_space_size=16384 ./node_modules/@angular/cli/bin/ng build --dev --aot --build-optimizer --environment=uat"
在原本的命令后面加上 && npm run version-plugin,修改后:
"produat": "npm run git-plugin --max_old_space_size=16384 && node --max_old_space_size=16384 ./node_modules/@angular/cli/bin/ng build --dev --aot --build-optimizer --environment=uat && npm run version-plugin"
然后运行流水线,可看到运行记录:
再查看移动端的部署日志可看到,已生成成功:
和pc一样,接下来在app.component.ts的路由里调用api,执行util里的versionExamine方法,进行对比处理:
如有版本更新会自动进行刷新浏览器的当前tab页,可同样看到【强制刷新页面~~】的log
声明
此功能上线之后,只有更新到这个方案的客户端才具备路由跳转进行版本更新的功能
此功能不具备解决线上有关逻辑性的报障,可解决一些因为版本落后导致的js/css/image等资源更新的情况
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!