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

概述

用户在访问单页面网站时,如果生产环境已经发布了新的版本(有功能上的变化),由于单页面中路由特性或浏览器缓存的原因,并不会重新加载前端资源,此时用户浏览器所并非加载是最新的代码,从而可能遇到一些 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>
相关推荐
sm_926787057 小时前
RFID 标签打印的技术实现要点与二次开发实践
java·大数据·前端·c++·编辑器
IMPYLH7 小时前
HTML 的 <video> 元素
前端·html
溪语流沙8 小时前
【每天一个CSS | Day19】流光文字与一笔写成的手写签名
前端·javascript·css
逐光者9338 小时前
STM32——SPI 屏 · Flash · 高速
java·前端·stm32
To_OC8 小时前
同样是让 AI 写全栈,为什么别人一句话就够了
前端·前端框架·next.js
CDwenhuohuo9 小时前
electron pc项目打包成桌面端
前端·javascript·electron
前端大斗师9 小时前
「大于 1000」把 1000 元那单也算进去了:我在 Vue3 订单页对了 10 句话
前端·人工智能·typescript·大模型·原力计划
Jmyd01239 小时前
用 Web VR 引擎搭建 3D 虚拟展厅:从素材上云到多端实时渲染的完整数据链路
前端·3d·vr·三维数字化
刘天远10 小时前
Agent成本核算实现:事件表、状态分布与Python归集
前端·数据库·人工智能·python
欣欣之王来了10 小时前
开发环境准备:Node.js、npm、VS Code安装配置
前端·学习·架构·项目·vue3教程