监控前端代码版本迭代实现页面自动刷新

您所在的位置:网站首页 php实现自动更新 监控前端代码版本迭代实现页面自动刷新

监控前端代码版本迭代实现页面自动刷新

2023-08-04 16:31| 来源: 网络整理| 查看: 265

监控前端代码版本迭代实现页面自动刷新 背景:

当前端版本迭代较为频繁的时候,使用webpack对项目进行打包,虽然我们对js和css文件使用了chunkhash进行了文件缓存控制,但是项目的index.html文件在版本频繁迭代更新时,会存在被浏览器缓存的情况。在发版后,用户不强制刷新页面,浏览器会使用缓存的index.html文件,从而导致向服务器端请求了上个版本chunkhash的js和css文件,最终页面404(上个版本chunkhash的js和css在版本更新时已替换删除了)。

output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].[chunkhash].js'), chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }

解决思路:

服务器端发版,上一个版本的代码不删掉;在每次打包生产代码时,在static下生产一个version.json的版本信息文件,在前端页面实时请求服务器端的version.json中的版本号和浏览器本地缓存的version.json进行对比,从而监控版本迭代更新,实现页面自动更新,获取新的index.html文件(前提是服务器端对index.html进行不缓存配置)。

思路1:缺点是会随着频繁发版,服务器端前端项目文件会越来越多,浪费空间,同时,旧页面的接口涉及到接口后端同学已经废弃了,引起报错;

所以现在主要以思路2进行处理:

配置环境 // config/dev.env.js 'use strict' const merge = require('webpack-merge') const prodEnv = require('./prod.env') module.exports = merge(prodEnv, { NODE_ENV: '"development"', VERSION: '""' }) // config/prod.env.js 'use strict' module.exports = { NODE_ENV: '"production"', // 区分开发/生产环境 VERSION: '"v' + new Date().getTime() + '"' // 版本格式 } 自定义版本信息生成插件: 如何编写一个插件? 'use strict'; var FStream = require('fs'); /** * 版本信息生成插件 * @author guoqian.xu * @param options * @constructor */ function VersionPlugin(options) { this.options = options || {}; !this.options.versionDirectory && (this.options.versionDirectory = 'static'); } // apply方法是必须要有的,因为当我们使用一个插件时(new somePlugins({})),webpack会去寻找插件的apply方法执行 VersionPlugin.prototype.apply = function (compiler) { var self = this; compiler.plugin('compile', function (params) { // 生成版本信息文件路径 // this.options.context:项目的绝对路径 var dir_path = this.options.context + '/' + self.options.versionDirectory; var version_file = dir_path + '/version.json'; var content = '{"version":' + self.options.env.VERSION + '}'; FStream.exists(dir_path, function (exist) { if (exist) { writeVersion(self, version_file, content); return; } FStream.mkdir(dir_path, function (err) { if (err) throw err; console.log('\n创建目录[' + dir_path + ']成功'); writeVersion(self, version_file, content); }); }); }); // 编译器对'所有任务已经完成'这个事件的监听 compiler.plugin('done', function (stats) { console.log('应用编译完成!'); }); }; const writeVersion = (self, versionFile, content) => { console.log('\n当前版本号:' + self.options.env.VERSION); console.log('开始写入版本信息...'); // 写入文件 FStream.writeFile(versionFile, content, function (err) { if (err) throw err; console.log('版本信息写入成功!'); }); }; module.exports = VersionPlugin; 加载插件 // webpack.prod.config.js // 版本信息生成 const VersionPlugin = require('./version-plugin'); ... const webpackConfig = merge(baseWebpackConfig, { ... plugins: [ // 版本信息生成 new VersionPlugin({ path: config.build.assetsRoot, env: env, versionDirectory: 'static' }), ... ] ... }); 选择你需要的位置进行监控(路由钩子、特定页面、接口调用拦截等) // 版本监控 async versionCheck() { if (NODE_ENV === 'development') return; const response = await this.$ajax.get(`../static/version.json`); if (VERSION !== response.data.version) { this.$alert('发现新版本,自动更新中...', '温馨提示', { confirmButtonText: '我知道了', type: 'warning', closeOnClickModal: false, closeOnPressEscape: false, showClose: false, callback: action => { window.location.reload(true); } }); } }

这里说一下在路由钩子的检测实现:

// router/index.js import Vue from 'vue'; import Router from 'vue-router'; import routeInterceptor from './hooks'; ... router.beforeEach(routeInterceptor); // hooks/index.js /* hooks 目录用于配置路由钩子 */ import routerViewChange from './routerViewChange'; ... const allHooks = [ /* 放置全部的路由钩子 */ routerViewChange ]; const routeInterceptor = ({ path: toPath, query: toQuery, matched }, { path: fromPath }, next) => { // 路由拦截 if (matched.length === 0) { // 404页面 next({ path: '/error/404' }); } else { // 找到匹配当前路由的钩子 const hookMatched = allHooks.filter(({ path: hookPath }) => { if (hookPath instanceof RegExp) { const routerPathReg = hookPath; return routerPathReg.test(toPath); } return hookPath === toPath; }); const hookLen = hookMatched.length; if (hookLen) { let hookActived = 0; // 匹配到路由钩子后, 触发该路由下的全部钩子函数 hookMatched.forEach((hook /* , idx */) => { hook.action({ toPath, fromPath, toQuery, next(params) { // 使用计数器控制 保证全部路由钩子均执行完毕 (包括异步调用 next 函数)后, 才继续路由导航 if (hookActived next(); } } }; export default routeInterceptor; // hooks/routerViewChange.js import { ajax } from '@/utils'; const routerViewChange = { path: /\/\w+?\//, // 匹配所有路由 action: async({ toPath, next }) => { if (NODE_ENV === 'development') return; const response = await ajax.get(`../static/version.json`); if (VERSION !== response.data.version) { window.confirm('发现新版本,自动更新中...'); window.location.reload(true); } next(); } }; export default routerViewChange; 作者使用的是nginx,这里实现nginx对index.html的不缓存处理 location ~ .*\.(htm|html)?$ { add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate"; # 指明root,如果不在外层上指明root,需要在这里指明 root /data/server/ui/vue-project/dist/; }

最后产出的结果:

版本打包 产出文件 效果



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3