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

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、效果

相关推荐
学术头条15 分钟前
清华、智谱团队:探索 RLHF 的 scaling laws
人工智能·深度学习·算法·机器学习·语言模型·计算语言学
18号房客19 分钟前
一个简单的机器学习实战例程,使用Scikit-Learn库来完成一个常见的分类任务——**鸢尾花数据集(Iris Dataset)**的分类
人工智能·深度学习·神经网络·机器学习·语言模型·自然语言处理·sklearn
wakangda21 分钟前
React Native 集成原生Android功能
javascript·react native·react.js
吃杠碰小鸡24 分钟前
lodash常用函数
前端·javascript
emoji11111133 分钟前
前端对页面数据进行缓存
开发语言·前端·javascript
Ven%36 分钟前
如何在防火墙上指定ip访问服务器上任何端口呢
linux·服务器·网络·深度学习·tcp/ip
一个处女座的程序猿O(∩_∩)O1 小时前
vue3 如何使用 mounted
前端·javascript·vue.js
迷糊的『迷』1 小时前
vue-axios+springboot实现文件流下载
vue.js·spring boot
User_undefined1 小时前
uniapp Native.js原生arr插件服务发送广播到uniapp页面中
android·javascript·uni-app
web135085886351 小时前
uniapp小程序使用webview 嵌套 vue 项目
vue.js·小程序·uni-app