一文详解前端重新部署后如何通知用户刷新网页

1、前言

在 Vue 前端项目打包更新后,我们部署了新的代码,而用户浏览器中的缓存却没有及时更新

没有刷新页面或长时间停留该页面中,还在访问老旧的版本。为了确保用户能够及时获得最新的功能和修复的 bug,我们需要通知用户刷新页面获取最新的代码

2、解决方案

1、前后端使用websocket配合通知更新

2、纯前端实现,编译打包项目时动态生成一个记录版本号的version.json文件,通过轮询,将静态文件version.json中的版本号与缓存中的版本号对比是否一致

本文案例中采用第二种纯前端实现方案,无需依托后端再起一个服务,并且通俗易懂

流程如下:

3、实现步骤

1、封装webpack插件

封装一个webpack插件,当每次执行编译或者打包时

webpack构建流程中都会插入动态生成一个带最新版本标识的文件version.json

apply方法是所有Webpack插件必须实现的方法,它接收一个compiler对象作为参数,通过它可以访问和修改Webpack编译过程。在这里,它监听了compiler.hooks.emit钩子,这是一个异步的emit阶段钩子,在此阶段Webpack将生成并输出所有资产(assets)

js 复制代码
// build/version.js

class VersionPlugin {
  constructor(version) {
    this.version = version; // 存储当前版本号
  }
  apply(compiler) {
    // Webpack编译过程 compiler.hooks.emit异步钩子
    compiler.hooks.emit.tapAsync("versionPlugin", (compilation, callback) => {
      let fileContent = JSON.stringify({
        version: this.version
      })
      // 将此列表作为新的文件资产插入到webpack生成中:
      compilation.assets["version.json"] = {
        source: function () {
          return fileContent
        },
        size: function () {
          return fileContent.length;
        },
      };
      callback();
    });
  }
}
module.exports = VersionPlugin;

2、引入插件 && 生成唯一hash值版本号

生成唯一hash值 版本号,这里用时间戳代替,如果要严谨一点可以参考如下两种方案

1)获取 Git 仓库当前所指向的最新提交(commit)的哈希值,既能保证唯一性,又能避免每次编译都会被当作更新,以git的提交记录为更新基准减少更新的频繁

js 复制代码
const cp = require("child_process");
let commitHash  = '0'
// 执行一个shell命令,使用git rev-parse --short HEAD来获取当前git仓库的commit哈希值
commitHash = cp.execSync("git rev-parse --short HEAD").toString().trim();

2) 引入uuid库,生成UUID(通用唯一标识符)

js 复制代码
import { v4 as uuidv4 } from 'uuid';
console.log(uuidv4()); // 生成 UUID 并打印

在vue-cli脚手架配置文件vue.config.js中引入插件

1、将生成的版本号传入插件类

2、将生成的版本号添加至全局环境变量

js 复制代码
// vue.config.js

const VersionPlugin = require("./build/version.js");
const version = Date.now() // 生成唯一值,可以改用其他hash值代替,这里用时间戳

module.exports = {
  // 部署应用包时的基本 URL
  publicPath: "./",
  // 是否需要生产环境的 source map(源映射文件,帮助开发者在浏览器的开发者工具中,将错误和日志定位到原始代码的具体位置)
  productionSourceMap: false,
  // 是否使用包含运行时编译器的 Vue 构建版本
  runtimeCompiler: true,
  // 是否在开发下通过eslint-loader在每次保存时lint代码, 需要安装@vue/cli-plugin-eslint
  lintOnSave: true,
  // webpack额外配置
  configureWebpack: {
    plugins: [
      new VersionPlugin(version) // 传入hash版本号
    ],
  },
  chainWebpack: config => {
    config.plugin('define')
      .tap(args => {
        // 添加全局环境变量
        args[0]['process.env'] = {
          ...args[0]['process.env'],
          version, // 将版本号添加至全局环境变量
        };
        return args;
      });
  },
}

3、缓存全局变量

main.js入口文件中,将全局环境变量中的版本号缓存至vue原型链上

js 复制代码
// main.js
import Vue from 'vue'
import App from './App.vue'

const { version } = process.env;
Vue.prototype.$version = version // 将版本号写入vue原型

Vue.config.productionTip = false

new Vue({
  render: h => h(App)
}).$mount('#app')

4、轮询监听版本号获取最新版本

在主页面app.vue中进行请求监听,这里为方便测试轮询间隔为5s,正式环境中可以延长此时间

打包后的version.js被一起部署到线上的静态资源服务中,可以直接通过 访问域名+/version.js即可直接访问,这里引用axios库进行默认的get请求访问

请求成功后将文件中最新的版本号 与当前运行网页中缓存的版本号比较,如果不一致则提示用户刷新网页

html 复制代码
<!-- app.vue -->
<template>
  <div id="app">
  </div>
</template>
<script>
import axios from "axios";
export default {
    data() {
        return {
            intervalTime: null, // 定时器
        }
    },
    methods: {
    // 检查版本更新
    checkVersion(time) {
      this.intervalTime = setInterval(() => {
        axios({
          url: `${window.location.origin}/version.json`, // 当前页面地址+json文件
          method: "get",
          timeout: 60000,
        })
          .then(({ status, data }) => {
            if (status === 200) {
              console.log(data.version, this.$version, "data");
              let version = data.version;
              let hash = this.$version;
              if (hash != version) {
                this.$confirm("系统已经更新,请刷新页面?", "提示", {
                  confirmButtonText: "确定",
                  cancelButtonText: "取消",
                  type: "warning",
                }).then(() => {
                  window.location.reload();
                });
              }
            }
          })
          .catch(() => {});
      }, time);
    },
    // 监听浏览器页面是否更新
    checkVersionHandler() {
      const time = 5000; // 刷新时间间隔5s
      this.checkVersion(time);
      this.$on("hook:beforeDestroy", () => {
        clearInterval(this.intervalTime);
        this.intervalTime = null;
      });
    },
  },
  created() {
    // 添加监听浏览器页面是否更新函数
    this.checkVersionHandler();
  },
}
</script>

4、效果

相关推荐
羊小猪~~7 分钟前
神经网络基础--什么是正向传播??什么是方向传播??
人工智能·pytorch·python·深度学习·神经网络·算法·机器学习
web行路人12 分钟前
React中类组件和函数组件的理解和区别
前端·javascript·react.js·前端框架
番茄小酱00113 分钟前
Expo|ReactNative 中实现扫描二维码功能
javascript·react native·react.js
子非鱼92131 分钟前
【Ajax】跨域
javascript·ajax·cors·jsonp
软工菜鸡33 分钟前
预训练语言模型BERT——PaddleNLP中的预训练模型
大数据·人工智能·深度学习·算法·语言模型·自然语言处理·bert
超雄代码狂34 分钟前
ajax关于axios库的运用小案例
前端·javascript·ajax
嚣张农民1 小时前
推荐3个实用的760°全景框架
前端·vue.js·程序员
周亚鑫1 小时前
vue3 pdf base64转成文件流打开
前端·javascript·pdf
落魄小二1 小时前
el-table 表格索引不展示问题
javascript·vue.js·elementui
y5236481 小时前
Javascript监控元素样式变化
开发语言·javascript·ecmascript