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

概述

用户在访问单页面网站时,如果生产环境已经发布了新的版本(有功能上的变化),由于单页面中路由特性或浏览器缓存的原因,并不会重新加载前端资源,此时用户浏览器所并非加载是最新的代码,从而可能遇到一些 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>
相关推荐
Giser探索家1 小时前
低空智航平台技术架构深度解析:如何用AI +空域网格破解黑飞与安全管控难题
大数据·服务器·前端·数据库·人工智能·安全·架构
John_ToDebug3 小时前
JS 与 C++ 双向通信实战:基于 WebHostViewListener 的消息处理机制
前端·c++·chrome
gnip3 小时前
监听设备网络状态
前端·javascript
As33100104 小时前
Chrome 插件开发实战:打造高效浏览器扩展
前端·chrome
xrkhy4 小时前
nvm安装详细教程(卸载旧的nodejs,安装nvm、node、npm、cnpm、yarn及环境变量配置)
前端·npm·node.js
德育处主任5 小时前
p5.js 3D盒子的基础用法
前端·数据可视化·canvas
前端的阶梯6 小时前
为何我的figma-developer-mcp不可用?
前端
weixin_456904276 小时前
Vue3入口文件main.js解析
前端·javascript·vue.js
Awbeci6 小时前
微前端-解决MicroApp微前端内存泄露问题
前端