前端项目部署自动检测更新后通知用户刷新页面(前端实现,技术框架vue、js、webpack)——方案一:编译项目时动态生成一个记录版本号的文件

慈云数据 1年前 (2024-04-13) 技术支持 71 0

前言

当我们重新部署前端项目的时候,如果用户一直停留在页面上并未刷新使用,会存在功能使用差异性的问题,因此,当前端部署项目后,需要提醒用户有去重新加载页面。

技术框架

vue、js、webpack

解决方案

  • 编译项目时动态生成一个记录版本号文件
  • 轮询(20s、自己设定时间)这个文件,判断版本号,有新版本则通知用户刷新页面
  • 通过监听visibilitychange事件,在页面隐藏时停止轮询,页面显示立马检测一次更新
  • 检测到更新后,停止轮询

    (感兴趣的可去看方案二:根据打完包之后生成的script src 的hash值去判断,每次打包都会生成唯一的hash值,只要轮询去判断不一样了,那一定是重新部署了。) 

    效果

    页面右下角提示更新:

    代码实现 

     Step1:在 vue.config.js 实现动态创建版本号文件

    if (process.env.VUE_APP_ENV !== "production") {
    // 这里我设置的是只在非生产环境自动检测更新(生成version);
    // 想要所有环境都自动检测更新,只要写if(process.env.VUE_APP_ENV !== "production")内的内容就好
      const { writeFile, existsSync } = require('fs')
      // 动态生成版本号
      const createVersion = () => {
        //检测目录是否存在
        if (existsSync('./public')) {
          writeFile(`./public/version.json`, `{"version":"${Date.now()}"}`, (err) => {
            if (err) {
              console.log('写入version.json失败')
              console.log(err)
            } else {
              console.log('写入version.json成功')
            }
          })
        } else {
          setTimeout(createVersion, 1000)
        }
      }
      setTimeout(createVersion, 10000)
    }

     Step2:在src目录下封装 auto-update.js

    /*
     * @Description: 自动更新
     */
    let currentVersion // 当前版本
    let version // 新版本
    // const timeData = 60 * 1000 // 检查间隔时间
    const timeData = 20 * 1000 // 检查间隔时间
    let hidden = false // 页面是否隐藏
    let setTimeoutId
    let needTip = true // 默认开启提示
    // 获取版本号
    const getVersion = async () => {
      return fetch('/version.json?timestep=' + Date.now()).then((res) => res.json())
    }
    // 检查更新
    const checkUpdate = async () => {
      console.log('***************checkUpdate**************')
      const currentVersion = sessionStorage.getItem("version")
      version = (await getVersion()).version
      // 本地没有 version,表示刚进入系统,直接塞值
      if (!currentVersion) return sessionStorage.setItem("version", version)
      console.log("🚀 ~ file: auto-update.js:19 ~ version:", version)
      console.log("🚀 ~ file: auto-update.js:21 ~ currentVersion:", currentVersion)
      console.log("🚀 ~ file: auto-update.js:23 ~ Number(version) !== Number(currentVersion):", Number(version) !== Number(currentVersion))
      let needRefresh = false
      if (Number(version) !== Number(currentVersion)) {
        console.log('%c 发现新版本~~~~~~', 'color: red')
        needRefresh = true
      }
      return needRefresh
    }
    // 自动更新
    const autoUpdate = async () => {
      setTimeoutId = setTimeout(async () => {
        // 页面隐藏了就不检查更新
        if (!hidden) {
          const willUpdate = await checkUpdate()
          console.log("🚀 ~ file: auto-update.js:71 ~ setTimeoutId=setTimeout ~ willUpdate, version:", willUpdate, version)
          if (willUpdate && needTip) {
            // 延时更新,防止部署未完成用户就刷新空白
            setTimeout(()=>{
              // ----弹框确认---先简单点弹框确认,可以用注释内的,跳过右下角通知的内容(Step3、4)
              // const result = confirm('发现新版本,点击确定更新')
              // if (result) {
              //   sessionStorage.setItem('version', version)
              //   location.reload() // 刷新当前页
              // }
              // --------------
              
              //*****右下角通知提示 */
              window.dispatchEvent(
                new CustomEvent("onmessageUpdate", {
                  detail: {
                    msg: "发现系统版本更新,请刷新页面~",
                    version: version
                  },
                })
              )
              //******************* */
            }, 10000)
            needTip = false // 关闭更新提示,防止重复提醒
          }
        }
        console.log("🚀 ~ file: auto-update.js:90 ~ autoUpdate ~ needTip: ", needTip)
        if (needTip) {
          console.warn('needTip autoUpdate');
          autoUpdate()
        }
      }, timeData)
    }
    // 停止检测更新
    const stop = () => {
      if (setTimeoutId) {
        clearTimeout(setTimeoutId)
        setTimeoutId = ''
      }
    }
    // 开始检查更新
    const start = async () => {
      // currentVersion = (await getVersion()).version
      autoUpdate()
      // 监听页面是否隐藏
      document.addEventListener('visibilitychange', () => {
        hidden = document.hidden
        console.log("🚀 ~ file: auto-update.js:64 ~ document.addEventListener ~ hidden, needTip:", hidden, needTip)
        // 页面隐藏了就不检查更新。或者已经有一个提示框了,防止重复提示。
        if (!hidden && needTip) {
          autoUpdate()
        } else {
          stop()
        }
      })
    }
    export default { start }
    

    Step3:编写模板 CnNotify.vue 文件

      
        
          
          {{ msg }}
        
        
          
            确认刷新
            我知道了
          
        
      
    
    
    export default {
      props: {
        msg: {
          type: String,
          default: '',
        },
        version: {
          type: String,
          default: '',
        },
      },
      data() {
        return {};
      },
      created() {},
      methods: {
        // 点击确定更新
        onSubmit() {
          sessionStorage.setItem('version', this.version) // 存入版本version
          location.reload() // 刷新
        },
        // 关闭
        cancle() {
          this.$parent.close();
        },
      },
    };
    
    
    .cn_notify {
      .content {
        padding: 20px 0;
      }
      .footer {
        display: flex;
        justify-content: center;
      }
    }
    
    
    .versionNotifyStyle {
      .el-notification__content {
        width: 280px !important;
      }
    }
    
    

    Step4:app.vue 使用组件CnNotify

      
        
      
    
    
    // 引入CnNotify组件
    import CnNotify from "@/components/common/CnNotify/index.vue"
    export default  {
      name:  'App',
      components: {
        CnNotify, // 注册组件
      },
      mounted() {
        this.watchUpdate()
      },
      methods: {
          watchUpdate() {
            window.addEventListener("onmessageUpdate", (res) => {
              console.log("🚀 ~ file: App.vue:20 ~ window.addEventListener ~ res:", res)
              let msg = res.detail.msg,
              version = res.detail.version
              this.$notify({
                title: "版本更新提示",
                duration: 0,
                position: "bottom-right",
                dangerouslyUseHTMLString: true,
                message: this.$createElement("CnNotify", {
                  // 使用自定义组件
                  ref: "CnNotify",
                  props: {
                    msg: msg,
                    version: version
                  },
                }),
                customClass:'versionNotifyStyle', //自定义类名
              })
            })
          },
      },
    }
    
    

     Step5:在 main.js 内使用

    // 引入自动更新提醒
    import autoUpdate from './auto-update'
    // 非生产环境使用
    process.env.VUE_APP_ENV !== 'production' && autoUpdate.start()
    
微信扫一扫加客服

微信扫一扫加客服