前端监听预生产环境代码是否更新并给与刷新提示

50 阅读1分钟

有时候,我们的代码更新后,需要在测试环境通知用户,手动刷新页面,以获得最新的交互体验,该怎么做呢?话不多说,直接show me code!

// updater.ts
interface Options {
  timer?: number
}

export class Updater {
  //存储第一次值也就是script 的hash 信息
  oldScript: string[]
  //获取新的值 也就是新的script 的hash信息
  newScript: string[]
  //小型发布订阅通知用户更新了
  dispatch: Record<string, any[]>
  constructor(options: Options) {
      this.oldScript = [];
      this.newScript = []
      this.dispatch = {}
      this.init() //初始化
      this.timing(options?.timer)//轮询
  }


  async init() {
      const html: string = await this.getHtml()
      this.oldScript = this.parserScript(html)
  }

  async getHtml() {
      const html = await fetch("/").then(res => res.text()).catch(e => console.log(e));//读取index html
      return html || ""
  }

  parserScript(html: string) {
      const reg = new RegExp(/<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/ig) //script正则
      return html.match(reg) as string[] //匹配script标签
  }

  //发布订阅通知
  on(key: "no-update" | "update", fn: any) {
      (this.dispatch[key] || (this.dispatch[key] = [])).push(fn)  
      return this;
  }

  compare(oldArr: string[], newArr: string[]) {
      const base = oldArr.length
      const arr = Array.from(new Set(oldArr.concat(newArr)))
      //如果新旧length 一样无更新
      if (arr.length === base) {
          console.info("系统无更新")
          this.dispatch["no-update"]?.forEach(fn => {
              fn()
          })
      
      } else {
          //否则通知更新
          this.dispatch["update"].forEach(fn => {
              fn()
          })
      }
  }

  timing(time = 10000) {
       //轮询
      setInterval(async () => {
          const newHtml = await this.getHtml()
          this.newScript = this.parserScript(newHtml)
          this.compare(this.oldScript, this.newScript)
      }, time)
  }

}

使用示例:

import { Updater } from "utils/updater";

const App = () => {
    useEffect(() => {
        // 检测是否网站有发布更新,避免页面Error
        const up = new Updater({ timer: 500000 })
        up.on("update", () => {
          Modal.destroyAll()
          Modal.confirm({
            title: "提示",
            centered: true,
            content: "网页功能已更新,需要刷新页面,是否刷新页面?",
            onOk: () => {
              window.location.reload()
            }
          })
        })
     },[])
    return (<div>....</div>)
}