当前位置:首页 » 《随便一记》 » 正文

前端项目部署自动检测更新后通知用户刷新页面(前端实现,技术框架vue、js、webpack)——方案二:轮询去判断服务端的index.html是否跟当前的index.html的脚本hash值一样

15 人参与  2024年02月07日 11:21  分类 : 《随便一记》  评论

点击全文阅读


前言

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

技术框架

vue、js、webpack

解决方案

根据打完包之后生成的script src 的hash值去判断,每次打包都会生成唯一的hash值,只要轮询去判断不一样了,那一定是重新部署了
轮询(20s、自己设定时间)服务器的index.html 文件,将新的script数组与旧script数组比较数组内容是否一致(可以将新旧数组拼接后去重,若去重后的数组长度,与旧数组长度不一样,则说明重新部署了),若新旧数组不一致则通知用户刷新页面通过监听visibilitychange事件,在页面隐藏时停止轮询,页面显示立马检测一次更新检测到更新后,停止轮询

(感兴趣的还可去看方案一:编译项目时动态生成一个记录版本号的文件,轮询请求该文件。)

效果

页面右下角提示更新:

代码实现 

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

/* * @Description: 自动更新 */// const timeData = 60 * 1000 // 检查间隔时间const timeData = 20 * 1000 // 检查间隔时间let hidden = false // 页面是否隐藏let setTimeoutIdlet needTip = true // 默认开启提示let oldScript = []let newScript  = []const getHtml = async () => {  const html = await fetch('/').then(res => res.text()) //读取index html  return html}// const scriptReg = /<script.*src=["'](?<src>[^"']+)/gmconst parserScript = (html) => {  const reg = new RegExp(/<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/ig) //script正则  return html.match(reg) //匹配script标签}const init = async () =>{  const html = await getHtml()  // console.log("? ~ file: auto-update.js:31 ~ init ~ html:", html)  oldScript = parserScript(html)  console.log("? ~ file: auto-update.js:30 ~ init ~ oldScript:", oldScript)}const compareScript = async (oldArr, newArr) => {  console.log('***************compareScript**************')  console.log("? ~ file: auto-update.js:37 ~ compareScript ~ oldArr, newArr:", oldArr, newArr)  const base = oldArr.length  console.log("? ~ file: auto-update.js:36 ~ compareScript ~ base:", base)  // 去重  const arr = Array.from(new Set(oldArr.concat(newArr)))  console.log("? ~ file: auto-update.js:39 ~ compareScript ~ arr:", arr, arr.length)  let needRefresh = false  // 如果新旧length 一样无更新  // 否则通知更新  if (arr.length !== base) {    console.warn('更新了!!!!!!, arr.length !== base', arr.length !== base)    needRefresh = true  }  // for (let i = 0; i < oldArr.length; i++) {  //   if (oldArr[i] !== arr[i]) {  //     needRefresh = true  //     console.warn('更新了!!!!!!, 值不等')  //     break  //   }  // }  return needRefresh}// 自动更新const autoUpdate = async () => {  setTimeoutId = setTimeout(async () => {    const newHtml = await getHtml()    // console.log("? ~ file: auto-update.js:89 ~ newHtml:", newHtml)    newScript = parserScript(newHtml)    console.log("? ~ file: auto-update.js:79 ~ newScript:", newScript)    // 页面隐藏了就不检查更新    if (!hidden) {      const willRefresh = await compareScript(oldScript, newScript)      console.log("? ~ file: auto-update.js:85 ~ setTimeoutId=setTimeout ~ willRefresh:", willRefresh)      if (willRefresh && needTip) {        // 延时更新,防止部署未完成用户就刷新空白        setTimeout(()=>{          // ----弹框确认---先简单点弹框确认,可以用注释内的,跳过右下角通知的内容(Step2、3)          // 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 () => {  init()  console.log('start0000000000')  autoUpdate()  console.log('start1111111111')  // 监听页面是否隐藏  document.addEventListener('visibilitychange', () => {    hidden = document.hidden    console.log("? ~ file: auto-update.js:64 ~ document.addEventListener ~ hidden, needTip:", hidden, needTip)    // 页面隐藏了就不检查更新。或者已经有一个提示框了,防止重复提示。    if (!hidden && needTip) {      console.log('!!!checkupdate', '222222222');      autoUpdate()    } else {      stop()    }  })}export default { start }

Step2:编写模板 CnNotify.vue 文件

<template>  <div class="cn_notify">    <div class="content">      <i class="el-icon-message-solid"></i>      {{ msg }}    </div>    <div class="footer">      <el-row class="btnBox">        <el-button type="primary" @click="onSubmit">确认刷新</el-button>        <el-button @click="cancle">我知道了</el-button>      </el-row>    </div>  </div></template><script>export default {  props: {    msg: {      type: String,      default: '',    },  },  data() {    return {};  },  created() {},  methods: {    // 点击确定更新    onSubmit() {      location.reload() // 刷新    },    // 关闭    cancle() {      this.$parent.close();    },  },};</script><style lang='scss' scoped>.cn_notify {  .content {    padding: 20px 0;  }  .footer {    display: flex;    justify-content: center;  }}</style><style lang='scss'>.versionNotifyStyle {  .el-notification__content {    width: 280px !important;  }}</style>

Step3:app.vue 使用组件CnNotify

<template>  <div id="app">    <router-view />  </div></template><script>// 引入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', //自定义类名          })        })      },  },}</script>

 Step4:在 main.js 内使用

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


点击全文阅读


本文链接:http://zhangshiyu.com/post/67681.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1