Skip to content

亮点

生产环境自动检测更新

解释代码(packages\frontEnd\src\utils\pageRefresh.ts):

ts
let lastSrcs: string[] = []

// 匹配 <script src="..."> 的正则
const scriptTagRegex = /<script[^>]+src=["']([^"']+)["']/gi

/**
 * 获取当前页面的所有 <script> 标签中的 src 列表
 */
async function getScriptSrcList(): Promise<string[]> {
  try {
    const html = await fetch(`/?_=${Date.now()}`).then(res => res.text())

    // 可能会存在多个 script 标签,所以需要循环匹配
    const srcList: string[] = []
    let match: RegExpExecArray | null

    // 使用正则提取所有的 script 标签 src 值
    // match[0]:完整匹配到的内容
    // match[1]:第一个括号中的内容,即 src 的值
    while ((match = scriptTagRegex.exec(html))) {
      srcList.push(match[1])
    }

    return srcList
  } catch (error) {
    console.error('获取页面 HTML 失败:', error)
    return []
  }
}

/**
 * 判断两个 src 列表是否有变化
 */
function hasChanged(oldList: string[], newList: string[]): boolean {
  if (oldList.length !== newList.length) return true

  for (let i = 0; i < oldList.length; i++) {
    if (oldList[i] !== newList[i]) {
      return true
    }
  }

  return false
}

/**
 * 启动轮询检测页面是否需要刷新
 * @param interval - 检测的时间间隔(毫秒)
 */
let hasShownNotification = false
export default function checkPageRefresh(interval: number = 5 * 1000): void {
  const check = async () => {
    const newSrcs = await getScriptSrcList()

    if (lastSrcs.length === 0) {
      lastSrcs = newSrcs
      return
    }

    if (hasChanged(lastSrcs, newSrcs) && !hasShownNotification) {
      hasShownNotification = true
      notification.info({
        message: '页面已更新,是否刷新?',
        description: (
          <div
            style={{
              marginTop: 8,
            }}
          >
            <Button
              onClick={() => {
                window.location.reload()
              }}
              type="primary"
              style={{
                marginRight: 8,
              }}
            >
              立即刷新
            </Button>
            <Button
              onClick={() => {
                // 用户拒绝刷新,也要记录新的 src 状态
                lastSrcs = newSrcs
                notification.destroy('refresh')
              }}
            >
              稍后刷新
            </Button>
          </div>
        ),
        duration: null,
        closeIcon: false,
        key: 'refresh',
      })
    }
  }

  check()
  setInterval(check, interval)
}

预览使用Element.attachShadow()

基于 MIT 许可发布