背景
由于在spa模式的应用中页面的内容变化不再引起整个页面的重新加载,故需要解决在spa模式的应用中网页在使用的过程中服务器已更新的资源不能被及时的获取的问题。
解决思路
- 标记版本:
- 在
vue.config.js中每次编译生成一个版本号 - 使用
html-webpack-plugin插件将版本号插入到index.html的mate标签 - 在
webpack编译结束生成附带版本号的version.json文件放置到服务器
- 检测版本
- 通过
document.getElementsByTagName("meta").buildVersion.content获取浏览器已打开网页的版本号 - 通过不带缓存的
get请求获取服务器存放的新版本号的version.json
- 刷新页面: 通过检测版本来提示或自动刷新页面获取最新的服务器资源
标记版本
- 配置
html-webpack-plugin为index.html插入编译版本号
const HtmlWebpackPlugin = require("html-webpack-plugin"); const buildVersion = Date.now(); console.log("当前编译版本: >>", buildVersion); module.exports = { configureWebpack: (config) => { config.plugins.forEach((plugin) => { if (plugin instanceof HtmlWebpackPlugin) { plugin.options.version = buildVersion; } }); }, };
- 在
index.html插入mate标签
<meta name="buildVersion" content="<%= htmlWebpackPlugin.options.version %>">
- 创建用于生成
version.json的webpack插件build-version.js
const pluginName = "BuildVersionWebpackPlugin"; const fs = require("fs"); const path = require("path"); /** * 编译后生成版本文件 */ class BuildVersionWebpackPlugin { constructor({ output = "./", version = Date.now() }) { this.output = output; this.version = version; } apply(compiler) { compiler.hooks.done.tap(pluginName, () => { console.log("webpack 编译完成,正在生成版本文件!"); const outputPath = path.resolve(this.output, "./version.json"); const versionJson = JSON.stringify({ version: this.version, }); fs.writeFileSync(outputPath, versionJson, { encoding: "utf-8", }); }); } } module.exports = BuildVersionWebpackPlugin;
- 配置新建的webpack插件
const BuildVersionWebpackPlugin = require("./build-version.js"); const buildVersion = Date.now(); console.log("当前编译版本: >>", buildVersion); module.exports = { configureWebpack: (config) => { ... config.plugins.push( new BuildVersionWebpackPlugin({ output: "./dist", version: buildVersion, }) ); }, };
检测版本
- 获取服务器存放的版本号
async function _serverVersion() { return await new Promise((resolve) => { fetch("/version.json", { headers: { "cache-control": "no-cache", }, }) .then((response) => { try { response.json().then((json) => { resolve(json.version); }); } catch (error) { resolve(0); } }) .catch(() => { resolve(0); }); }); }
- 获取浏览器本地页面的版本号
function _currentVersion() { return Number(document.getElementsByTagName("meta").buildVersion.content); }
- 版本号比较
async function _inspector() { let isConsistent = true; const sv = await _serverVersion(); const cv = _currentVersion(); console.log(`检测到本地版本${cv}和服务器版本${sv}`); console.log("本地&服务器版本是否一致:>>", (isConsistent = sv === cv)); return isConsistent; } export default async function() { return await _inspector(); }
刷新页面
- 检测更新时机: 推荐在路由切换之后检测,或主要模块进入时检测
- 检测函数,具体的刷新逻辑按实际场景考虑
versionCheck() { inspector().then((isConsistent) => { if (!isConsistent) { const isReload = window.confirm( "检测到本地版本和服务器版本不一致,点击确定更新页面 " ); if (isReload) { window.location.reload(); } } }); }
效果图
