前端实现自动检测项目部署更新

概述

用户在访问单页面网站时,如果生产环境已经发布了新的版本(有功能上的变化),由于单页面中路由特性或浏览器缓存的原因,并不会重新加载前端资源,此时用户浏览器所并非加载是最新的代码,从而可能遇到一些 bug。因此,部署之后,需要提醒用户版本更新,并引导用户刷新页面。

方案

使用轮询的方式请求index.html文件,从中解析里面的js文件,由于工程项目打包后每个js文件都有指纹标识(打包工具自动处理了文件hash,打包后没有需要配置文件hash),因此对比每次打包后的指纹,分析文件是否存在变动,如果有变动则提示用户更新,流程如下:

实现

新建auto-update.ts,内容如下

js 复制代码
import { ElMessageBox } from 'element-plus'

// 上一次获取到的script地址列表,用于比较是否有更新
let initScriptSrcList: string[] = [];

// 正则表达式用于匹配HTML中的script标签的src属性
const scriptReg = /<script.*src=["'](?<src>[^"']+)/gm;

/**
 * 从当前页面HTML中提取所有script标签的src地址
 * @returns {Promise<string[]>} 返回包含所有script src的数组
 */
const extractNewScripts = async () => {
    // 添加时间戳参数避免缓存
    const param = Date.now()
    // 获取当前页面HTML内容
    const html = await fetch('/?_time=' + param).then((resp) => resp.text());
    
    // 重置正则表达式匹配位置
    scriptReg.lastIndex = 0;
    let result = [];
    let match: RegExpExecArray
    
    // 遍历匹配所有script标签的src属性
    while ((match = scriptReg.exec(html) as RegExpExecArray) {
        result.push(match.groups?.src)
    }
    return result;
}

/**
 * 检查是否有新的脚本更新
 * @returns {Promise<boolean>} 返回true表示有更新,false表示无更新
 */
const isUpdate = async () => {
    // 获取当前页面所有script的src
    const newScripts: string[] = await extractNewScripts();
    
    // 如果是第一次检查,初始化脚本列表并返回无更新
    if (!initScriptSrcList.length) {
        initScriptSrcList = newScripts;
        return false;
    }
    
    let res = false;
    
    // 比较脚本数量是否有变化
    if (initScriptSrcList.length !== newScripts.length) {
        res = true;
    }
    
    // 逐个比较脚本地址是否有变化
    for (let i = 0; i < initScriptSrcList.length; i++) {
        if (initScriptSrcList[i] !== newScripts[i]) {
            res = true;
            break
        }
    }
    
    // 更新初始脚本列表为当前最新
    initScriptSrcList = newScripts;
    return res;
}

// 检查间隔时间(5秒)
const DELAY_TIME = 5000;

/**
 * 自动刷新功能入口
 * 每隔指定时间检查一次脚本更新,有更新时提示用户刷新页面
 */
export const autoRefresh = () => {
    setTimeout(async () => {
        // 检查是否需要更新
        const needUpdate = await isUpdate();
        
        if (needUpdate) {
            console.log('检测到页面有内容更新,自动刷新');
            
            // 使用Element Plus的MessageBox提示用户
            ElMessageBox.confirm('检测到页面有内容更新,是否立即刷新?', '更新提示', {
                confirmButtonText: '确认',
                showCancelButton: false,  // 不显示取消按钮
                type: 'warning'          // 警告类型提示框
            }).then(() => {
                // 用户确认后刷新页面
                location.reload();
            })
        }
        
        // 递归调用自身,实现持续检查
        autoRefresh();
    }, DELAY_TIME)
}

使用

我这里使用的是vite+vue的形式,在app.vue文件中

js 复制代码
<script setup lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
import { onMounted } from "vue";
import { autoRefresh } from "./utils/auto-update";

onMounted(() => {
//生产环境开启检测
  if (import.meta.env.MODE == "production") {
    autoRefresh();
  }
});
</script>
相关推荐
0***R5158 小时前
前端构建工具缓存,node_modules
前端·缓存
坚持就完事了8 小时前
CSS-4:CSS的三大特性
前端·css
坚持就完事了8 小时前
CSS-3:背景设置
前端·css·html
坚持就完事了8 小时前
CSS-2:CSS的元素显示模式
前端·css
肠胃炎8 小时前
Flutter 基础组件
前端·flutter
酥风8 小时前
AI概念解惑系列 - RAG
前端·llm·aigc
IT_陈寒8 小时前
Redis深度优化:10个让你的QPS提升50%的关键配置解析
前端·人工智能·后端
Hilaku9 小时前
别再吹性能优化了:你的应用卡顿,纯粹是因为产品设计烂🤷‍♂️
前端·javascript·代码规范
驯狼小羊羔9 小时前
学习随笔-hooks和mixins
前端·javascript·vue.js·学习·hooks·mixins
r***86989 小时前
Redis 6.2.7安装配置
前端·数据库·redis