前端实现版本更新自动检测✅

在这里插入图片描述

🤖 作者简介:水煮白菜王,一位资深前端劝退师 👻
👀 文章专栏: 前端专栏 ,记录一下平时在博客写作中,总结出的一些开发技巧和知识归纳总结✍。
感谢支持💕💕💕

目录

  • 一、应用场景
  • 二、实现原理
    • 2.1 核心检测逻辑
    • 2.2 实现优势
  • 三 、具体实现
    • 3.1 工程化封装
    • 3.2 关键方法解析
      • 脚本哈希获取:
      • 对比逻辑:
  • 四、全部代码🚀🚀🚀
    • 4.1 vue3
    • 4.2 vue2
  • 五、注意事项与常见问题
    • 5.1 可能出现的问题
    • 5.2 浏览器兼容方案

一、应用场景

在现代Web应用中,为了提升用户体验并确保系统的稳定性和一致性,部署前端版本更新后及时提醒用户进行页面刷新是至关重要的。当生产环境发布了包含功能变化的新版本时,由于单页面(SPA)应用的路由特性和浏览器缓存机制,用户浏览器可能不会自动加载最新的代码资源,这可能导致用户遇到bug或体验到不一致的功能行为。通过实现自动检测机制来提醒用户版本更新,并引导其刷新页面,可以

  1. 避免用户使用过期版本
  2. 确保功能一致性
  3. 减少接口兼容性问题
  4. 提高应用可靠性

二、实现原理

2.1 核心检测逻辑

变化
未变化
应用启动
生产环境?
启动定时器
结束流程
等待60秒
获取当前脚本哈希
首次运行?
保存初始哈希
哈希变化?
停止定时器
显示更新提示
用户确认?
刷新页面
记录取消操作

通过对比构建产物的哈希值变化实现版本检测:

  1. 定时轮询:每分钟检查静态资源变化
  2. 哈希对比:通过解析HTML中script标签指纹判断更新
  3. 强制刷新:检测到更新后提示用户刷新页面
// 核心对比逻辑
const isChanged = (oldSet, newSet) => {return oldSet.size !== newSet.size || ![...oldSet].every(hash => newSet.has(hash))
}

2.2 实现优势

  • 通用性强:适用于任意前端框架
  • 无侵入式检测:不依赖构建工具配置
  • 用户可控:提示框让用户选择刷新时机
  • 精准检测:通过对比script标签内容哈希值
  • 低资源消耗:每分钟检测一次,单次请求性能消耗低

三 、具体实现

3.1 工程化封装

// useVersionHash.js 核心实现
export default function useVersionHash() {// 状态管理const timerUpdate = ref(null)let scriptHashes = new Set()// 生命周期onMounted(() => startTimer())onBeforeUnmount(() => stopTimer())// 业务方法const fetchScriptHashes = async () => { /*...*/ }const compareScriptHashes = async () => { /*...*/ }return { compareScriptHashes }
}

3.2 关键方法解析

脚本哈希获取:

const fetchScriptHashes = async () => {const html = await fetch('/').then(res => res.text())const scriptRegex = /<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/gireturn new Set(html?.match(scriptRegex) || [])
}

对比逻辑:

if (scriptHashes.size === 0) {// 初始化基准值scriptHashes = newScriptHashes  
} else if (scriptHashes.size !== newScriptHashes.size ||![...scriptHashes].every(hash => newScriptHashes.has(hash))
) {// 触发更新流程stopTimer()showUpdateDialog()
}

四、全部代码🚀🚀🚀

4.1 vue3

1、use-version-update.js具体逻辑

// @/utils/use-version-update.js
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { ElMessageBox } from 'element-plus'let scriptHashes = new Set()
const timerUpdate = ref(null)export default function useVersionHash() {const isProduction = import.meta.env.MODE === 'production'const fetchScriptHashes = async () => {try {const html = await fetch('/').then((res) => res.text())const scriptRegex = /<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/gireturn new Set(html?.match(scriptRegex) || [])} catch (error) {console.error('获取脚本哈希失败:', error)return new Set()}}const compareScriptHashes = async () => {try {const newScriptHashes = await fetchScriptHashes()if (scriptHashes.size === 0) {scriptHashes = newScriptHashes} else if (scriptHashes.size !== newScriptHashes.size ||![...scriptHashes].every(hash => newScriptHashes.has(hash))) {stopTimer()updateNotice()}} catch (error) {console.error('版本检查失败:', error)}}const updateNotice = () => {ElMessageBox.confirm('检测到新版本,建议立即更新以确保平台正常使用','更新提示',{confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => window.location.reload())}const startTimer = () => {if (!isProduction) returntimerUpdate.value = setInterval(compareScriptHashes, 60000)}const stopTimer = () => {timerUpdate.value && clearInterval(timerUpdate.value)}onMounted(startTimer)onBeforeUnmount(stopTimer)return { compareScriptHashes, updateNotice }
}

2、引入use-version-update.js

// App.vue
import versionUpdatefrom '@/utils/use-version-update.js'
export default {setup() {const { updateNotice } = versionUpdate()return { updateNotice }}
}

3、Vite 相关配置

// vite.config.js
import { defineConfig } from 'vite'export default defineConfig({build: {rollupOptions: {output: {// 主入口文件命名规则entryFileNames: 'js/[name]-[hash:8].js',// 代码分割块命名规则chunkFileNames: 'js/[name]-[hash:8].js',// 静态资源文件命名规则assetFileNames: ({ name }) => {const ext = name?.split('.').pop()return `assets/${ext}/[name]-[hash:8].[ext]`}}},// 启用文件哈希的manifest生成manifest: true}
})

也可以将use-version-update写成以JS、TS模块化封装,在入口文件中main.ts引入

// use-version-update.ts
export const versionUpdate = () => {... 具体处理逻辑
}// main.ts
import { versionUpdate} from "@/utils/use-version-update"
if (import.meta.env.MODE == 'production') {versionUpdate()
}

4.2 vue2

1、use-version-update.js具体逻辑

/** @Author: baicaiKing* @Date: 2025-01-02 13:50:33* @LastEditors: Do not edit* @LastEditTime: 2025-01-03 09:40:36* @FilePath: \code\src\utils\use-version-update.js*/
// 存储当前脚本标签的哈希值集合
let scriptHashes = new Set();
let timerUpdate = undefined;
export default {data() {return {};},created() {},mounted() {// 每60秒检查一次是否有新的脚本标签更新if (process.env.NODE_ENV === 'production') { // 只针对生产环境timerUpdate= setInterval(() => {this.compareScriptHashes()}, 60000);}},beforeDestroy() {clearInterval(timerUpdate);timerUpdate = null;},methods: {/*** 从首页获取脚本标签的哈希值集合* @returns {Promise<Set<string>>} 返回包含脚本标签的哈希值的集合*/async fetchScriptHashes() {// 获取首页HTML内容const html = await fetch('/').then((res) => res.text());// 正则表达式匹配所有<script>标签const scriptRegex = /<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/gi;// 获取匹配到的所有<script>标签内容// const scripts = html.match(scriptRegex) ?? [];const scripts = html ? html.match(scriptRegex) || [] : [];// 将脚本标签内容存入集合并返回return new Set(scripts);},/*** 比较当前脚本标签的哈希值集合与新获取的集合,检测是否有更新*/async compareScriptHashes() {// 获取新的脚本标签哈希值集合const newScriptHashes = await this.fetchScriptHashes();if (scriptHashes.size === 0) {// 初次运行时,存储当前脚本标签哈希值scriptHashes = newScriptHashes;} else if (scriptHashes.size !== newScriptHashes.size ||![...scriptHashes].every((hash) => newScriptHashes.has(hash))) {// 如果脚本标签数量或内容发生变化,则认为有更新console.info('已检测到更新文件', {oldScript: [...scriptHashes],newScript: [...newScriptHashes],});// 清除定时器clearInterval(timerUpdate);// 提示用户更新this.updateNotice();} else {// 没有更新console.info('未检测到更新时机', {oldScript: [...scriptHashes],});}},updateNotice() {this.$confirm('检测到新版本,建议立即更新以确保平台正常使用', '更新提示', {confirmButtonText: '确定',cancelButtonText: '取消(自行刷新)',type: 'warning'}).then(() => {window.location.reload();}).catch(() => {console.eror('用户取消刷新!');});}},};

2、引入use-version-update.js

// App.vue
import versionUpdate from "@/util/use-version-update.js";
export default {name: "app",mixins: [versionUpdate],data() {return {};},
};

3、Webpack 相关配置


// vue.config
module.exports = {configureWebpack: {output: {filename: 'js/[name].[hash].js',// filename: 'js/[name].[contenthash].js',},},devServer: {},
};

五、注意事项与常见问题

5.1 可能出现的问题

问题现象可能原因解决方案
检测不准确正则匹配失效更新正则表达式
生产环境未生效环境变量配置错误检查构建配置
跨域请求失败部署路径不匹配调整fetch请求路径
内存泄漏定时器未正确清除使用WeakRef优化

5.2 浏览器兼容方案

可结合Service Worker实现无缝更新

// 支持Service Worker的渐进增强方案
if ('serviceWorker' in navigator) {navigator.serviceWorker.register('/sw.js').then(reg => {reg.addEventListener('updatefound', () => {showUpdateNotification()})})
}

同时要确保服务器配置正确缓存策略,通常Nginx缓存策略默认不用打理

在这里插入图片描述
如果你觉得这篇文章对你有帮助,请点赞 👍、收藏 👏 并关注我!👀
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/29318.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GitHub教程

目录 1.是什么?2.安装3.创建库3.增删改查4.远程仓库5.分支6.标签7.使用流程8.总结 1.是什么? Git 是一个命令行工具&#xff0c;但也有许多图形用户界面可用。本地仓库&#xff0c;安装包下载到本地。Git 的一个流行 GUI 是 GitHub&#xff0c;它可以方便地管理存储库、推送…

VsCode + EIDE + OpenOCD + STM32(野火DAP) 开发环境配置

VsCode EIDE OpenOCD STM32(野火DAP) 开发环境配置 接受了新时代编辑器的我&#xff0c;实在受不了Keil的上古编辑页面&#xff0c;周树人说过&#xff1a;由奢入俭难&#xff0c;下面我们一起折腾一下开源软件Vscode&#xff0c; 用以开发51和STM32&#xff0c;有错误之处&…

【MySQL】表的增删查改(CRUD)(下)

个人主页&#xff1a;♡喜欢做梦 欢迎 &#x1f44d;点赞 ➕关注 ❤️收藏 &#x1f4ac;评论 本篇是继上篇的下篇&#xff0c;如果上篇没有看过小伙伴&#xff0c;可以先看看我的上一篇再来看一下这一篇【MySQL】表的增删查改&#xff08;CRUD&#xff09;&#xff08;上…

知识周汇 | Python操作Excel全攻略系列(一):模块详解篇

目录 系列文章 前言 1 知识概览 2 模块详解 2.1 openpyxl 2.2 pandas 2.3 xlrd 2.4 xlwt 2.5 xlsxwriter 2.6 xlwing 3 后续 系列文章 知识周汇 | Python操作Excel全攻略系列&#xff08;二&#xff09;&#xff1a;文件操作篇 知识周汇 | Python操作Excel全攻略系…

NVIDIA GPU 架构详解:Pascal、Volta、Turing、Ampere、Ada、Hopper、Blackwell

目录 1. Pascal&#xff08;帕斯卡&#xff09;架构&#xff08;2016&#xff09;关键技术性能特性代表产品应用场景 2. Volta&#xff08;伏特&#xff09;架构&#xff08;2017&#xff09;关键技术性能特性代表产品应用场景 3.Turing&#xff08;图灵&#xff09;架构&#…

SpringMVC学习(controller层加载控制与(业务、功能)bean加载控制、Web容器初始化配置类)(3)

目录 一、SpringMVC、Spring的bean加载控制。 &#xff08;1&#xff09;实际开发的包结构层次。 &#xff08;2&#xff09;如何"精准"控制两个容器分别加载各自bean。(分析) <1>SpringMVC相关bean加载控制。(方法) <2>Spring相关bean加载控制。(方法) …

通过Docker搭个游戏——疯狂大陆(Pkland)

最近在研究我的服务器&#xff0c;在服务器上搭了很多docker的项目&#xff0c;然后找着找着发现一个能用Docker配置环境的游戏叫Pkland。 项目地址&#xff1a;GitHub - popkarthb/pkland: 疯狂大陆是一款多人在线的战略游戏。 游戏操作简捷,您仅需要使用浏览器就可以在任何时…

【SpringBoot】深入解析 Maven 的操作与配置

Maven 1.什么是Maven? Maven是一个项目管理工具&#xff0c;通过pom.xml文件的配置获取jar包&#xff0c;而不用手动去添加jar包&#xff1b; 2. 创建一个Maven项目 IDEA本身已经集成了Maven&#xff0c;我们可以直接使用&#xff0c;无需安装 以下截图的idea版本为&#xff…

Cursor + IDEA 双开极速交互

相信很多开发者朋友应该和我一样吧&#xff0c;都是Cursor和IDEA双开的开发模式:在Cursor中快速编写和生成代码&#xff0c;然后在IDEA中进行调试和优化 在这个双开模式的开发过程中&#xff0c;我就遇到一个说大不大说小不小的问题&#xff1a; 得在两个编辑器之间来回切换查…

HarmonyOS:如何将图片转为PixelMap并进行图片缓存策略

前言&#xff1a;在HarmonyOS项目开发中&#xff0c;我们使用Ark-Ts语言开发项目。我们有个功能是拍照&#xff0c;除了正常显示出来&#xff0c;并且上传服务器。我在开发过程中&#xff0c;遇到的问题是&#xff0c;如果离开这个页面再回到当前页面仍要显示图片&#xff0c;那…

ctf网络安全比赛有一张图片怎么查看

0102-JavaScript简介&&作用 02简介 JavaScript 是互联网上最流行的脚本语言&#xff0c;这门语言可用于 HTML 和 web&#xff0c;更可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。 03作用 JavaScript 是脚本语言 JavaScript 是一种轻量级的编程语…

搭建一个简单的node服务,模拟后端接口

目录 一、查看是否安装了node和npm 二、创建一个文件夹&#xff0c;用于放你的node服务代码 三、初始化一个package.json 四、安装 Express&#xff08;快速搭建服务的框架&#xff09; 五、创建serve.js 六、运行服务即可 七、测试接口 法一&#xff1a;使用 curl 法…

【五.LangChain技术与应用】【31.LangChain ReAct Agent:反应式智能代理的实现】

一、ReAct Agent是啥?为什么说它比「普通AI」聪明? 想象一下,你让ChatGPT查快递物流,它可能直接编个假单号糊弄你。但换成ReAct Agent,它会先推理(Reasoning)需要调用哪个接口,再行动(Action)查询真实数据——这就是ReAct的核心:让AI学会「动脑子」再动手。 举个真…

BUUCTF逆向刷题笔记(1-12)

easyre、内涵的软件、xor、不一样的flag&#xff1a; buuctf reverse部分题解&#xff08;实时更新&#xff09;_reverse 题解-CSDN博客 请见小库里的blog。 reverse1 查壳发现没有&#xff0c;而且是64位 粗略改一下部分函数名&#xff0c;看看主要逻辑。 第一个for循环暂…

OceanBase-obcp-v3考试资料梳理

集群架构 基本概念 集群: 集群由一个或多个Region组成,Region 由一个或多个Zone组成,Zone由一个或多个OBServer组成,每个OBServer里有若干个partition的Replica。 Region: 对应物理上的一个城市或地域,当OB集群由多个Region组成时, 数据库的数据和服务能力就具备地域…

【C++】双指针算法

我们还有更长的路要走&#xff0c;不过没关系&#xff0c;道路就是生活。 前言 这是我自己学习蓝桥杯算法的第一篇博客总结。后期我会继续把蓝桥杯算法学习笔记开源至博客上。 技巧 1. 双指针算法&#xff0c;但实际上是利用数组下标来充当指针&#xff0c;并不是直接使用指…

如何使用MyBatis进行多表查询

前言 在实际开发中&#xff0c;对数据库的操作通常会涉及多张表&#xff0c;MyBatis提供了关联映射&#xff0c;这些关联映射可以很好地处理表与表&#xff0c;对象与对象之间的的关联关系。 一对一查询 步骤&#xff1a; 先确定表的一对一关系确定好实体类&#xff0c;添加关…

江科大51单片机笔记【9】DS1302实时时钟(上)

一、DS1302介绍 DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时&#xff0c;且具有闰年补偿等多种功能。RTC&#xff08;Real Time Clock&#xff09;&#xff1a;实时时钟&#xff0c;是一种集成电路…

【Python项目】基于深度学习的车辆特征分析系统

【Python项目】基于深度学习的车辆特征分析系统 技术简介&#xff1a;采用Python技术、MySQL数据库、卷积神经网络&#xff08;CNN&#xff09;等实现。 系统简介&#xff1a;该系统基于深度学习技术&#xff0c;特别是卷积神经网络&#xff08;CNN&#xff09;&#xff0c;用…

汽车智能钥匙中PKE低频天线的作用

PKE&#xff08;Passive Keyless Entry&#xff09;即被动式无钥匙进入系统&#xff0c;汽车智能钥匙中PKE低频天线在现代汽车的智能功能和安全保障方面发挥着关键作用&#xff0c;以下是其具体作用&#xff1a; 信号交互与身份认证 低频信号接收&#xff1a;当车主靠近车辆时…