vue3+vite纯前端实现自动触发浏览器刷新更新版本内容,并在打包时生成版本号文件

前言

在前端项目中,有时候为了实现自动触发浏览器刷新并更新版本内容,可以采取一系列巧妙的措施。我的项目中是需要在打包时候生成一个version.js文件,用当前打包时间作为版本的唯一标识,然后打包发版 ,从实现对版本更新的监控。

因为项目使用 vite 打包的,vite又是基于rollup打包,rollup不像webpack有contentHash可以实现增量构建;而是每次打包,所有文件的hash都会更新,这样就会导致浏览器缓存的资源失效。
当用户已经打开页面,此时前端重新部署代码发版,会导致index.html未更新,而项目静态资源已经替换。当用户切换路由时,因为按需加载的原因,会继续访问旧的资源。

项目是基于 vue 3.4.21 + vite 4.3.9 + typescript 5.1.3 + node 16.1.0 开发的。

解决思路
  • 注入版本信息:通过vite构建打包时,注入一个版本信息的version.js 文件,文件内容是一个版本号(这里用时间戳代替)。
  • 定义监控版本函数并执行:定义一个函数并调用执行,该函数内容为生产环境下,从本地缓存中获取版本号,如果没有版本号或者和缓存中的版本号不一致,表示版本已更新。就刷新页面,然后本地存储新的版本号以便下次使用。
  • 在合适的时机(路由载入前),判断是否已经有 version.js 文件,如果有,先删除掉,再重新创建一个<script> 标签并赋值,值为最新版本号(时间戳)。
了解fs模块

开始之前先了解下fs模块吧,本文会使用到。

  • fs 通常是指 Node.js 中的 fs 模块,它是文件系统模块(File System
    module)的简写。 这个模块允许你与文件系统进行交互,包括读取、写入、修改、删除文件等操作 。在 Node.js 中,fs模块是内置的核心模块之一,因此 无需额外安装即可使用
  • fs 模块提供了丰富的 API 来处理文件和目录,包括同步和异步的操作方式。在使用 fs 模块时,需要特别注意错误处理,因为文件操作可能会涉及到磁盘访问和系统资源,因此 处理错误非常重要

其中的 fs.writeFile() 方法用于异步地将数据写入文件。其基本语法如下:

fs.writeFile(file, data, options, callback)

参数说明:

  • file(必需):表示要写入的文件的路径(包括文件名)。

  • data(必需):表示要写入文件的数据,可以是字符串或者 Buffer 对象。

  • options(可选):一个对象,包含指定如何写入文件的选项。常用选项包括:encoding:指定文件的编码,默认为 ‘utf8’。 mode:指定文件的权限,默认为 0o666(可读写)。 flag:指定文件的打开行为,默认为 ‘w’(覆盖写入)。

  • callback(可选):写入操作完成后的回调函数,通常以 (err)形式接收一个可能的错误参数。如果未提供回调函数,则返回一个 Promise。

使用解释:

  • fs.writeFile() 方法将 data 写入到指定的 file 中。如果文件不存在,则会创建该文件;如果文件已存在,则会完全覆盖原有内容。
  • 是异步的,意味着它会立即返回并且不会阻塞后续的代码执行;如果需要在写入文件后执行某些操作,可以使用回调函数或者 Promise
  • 若要进行文件写入操作,通常建议先检查是否有写入权限,并且考虑错误处理以确保应用程序的稳定性。

上面纯前端实现的做法,相对来说比较简单,实现的方式还有很多,比如自定义一个plugin插件 vite实现前端项目打包更新通知用户更新
使用WebSocket实时通信、前端轮询接口检测版本更新等等。感兴趣的可以继续搜资料看。

创建 build.ts 文件

src/utils/文件夹下创建 build.ts文件

// build.ts
import pkg from '../../package.json'
import { resolve } from 'path'
import fs from 'fs'

const version = new Date().getTime()
const content = `getVersion(${version})`

// 创建版本文件
fs.writeFile(`${resolve(__dirname, '../../dist')}/version.js`, content, (err) => (err ? console.log(err) : console.log('版本文件创建成功')))

export const run = () => {
  console.log(`${pkg.name} - build successfully!`)
}

如果上面这种node提示报错的话,可替换为下面这种

import pkg from '../../package.json'
import fs from 'fs'
import { fileURLToPath, URL } from 'node:url'

const version = new Date().getTime()
const content = `getVersion(${version})`

// 创建版本文件
fs.writeFile(fileURLToPath(new URL('../../dist/version.js', import.meta.url)), content, (err) =>
    err ? console.log(err) : console.log('版本文件创建成功')
)
export const run = () => {
    console.log(`? ${pkg.name} - build successfully!`)
}
run()
在package.json文件中配置执行 npm run build 时执行的任务

命令行安装 esno,esno是一个基于 esbuild 的 TS/ESNext 的 Node.js 运行时。

npm install esno

在package.json的build命令上加一行执行 esno ./src/utils/build.ts

{
   "name": "ceshi",
   "version": "1.0.0",
   "scripts": {
      "dev": "vite --force",
      "build": "vite build && esno ./src/utils/build.ts"
    }
}
创建 version.ts 文件

src/utils/文件夹下创建 version.ts文件

import Cookies from 'js-cookie'
import { ElLoading } from 'element-plus'

const versionKey = 'version-id'

export function getVersionId() {
    return Cookies.get(versionKey) ? Number(Cookies.get(versionKey)) : 0
}

export function setVersionId(version: number) {
    return Cookies.set(versionKey, String(version))
}

export function removeVersionId(version: number) {
    Cookies.remove(versionKey)
}

export function handleVersion() {
    if (process.env.NODE_ENV !== 'development') {
        window.getVersion = (version: number) => {
            if (!getVersionId() || (getVersionId() * 1 && version * 1 !== getVersionId() * 1)) {
                ElLoading.service() // 启动全屏ElLoading
                location.reload() // 刷新页面
            }
            setVersionId(version) // 保存 以便下次使用判断
        }
    }
}

export function insertVersionFile() {
    if (process.env.NODE_ENV !== 'development') {
        const scriptCollection = document.getElementsByTagName('script')
        // 判断是否已经有version.js 文件,如果有,先删掉资源引入
        // const scriptAry =[...scriptCollection] // ie不支持这种写法(HTMLCollection 不是数组)
        const scriptAry = Array.from(scriptCollection)
        scriptAry.some((v) => {
            const flag = v.src.indexOf('version.js') !== -1
            if (flag) {
                v.parentNode?.removeChild(v)
            }
            return flag
        })

        const versionScript = document.createElement('script')
        versionScript.src = import.meta.env.VITE_BASE_PATH + 'version.js?v=' + new Date().getTime()
        //document.getElementsByTagName('script')表示返回当前页面中所有 <script> 元素的集合
        const s = document.getElementsByTagName('script')[0]  
        s.parentNode?.insertBefore(versionScript, s)
    }
}
handleVersion()
router =》index.ts 中在前置路由,插入并且检查版本号

在路由跳转时进行实时的版本检测,本质就是在路由拦截器去做这个操作。

import { insertVersionFile } from '/@/utils/version'

const router = createRouter({
    history: createWebHashHistory(),
    routes: staticRoutes,
})

router.beforeEach((to, from, next) => {
    // 插入并且检查版本号
    insertVersionFile()
    NProgress.configure({ showSpinner: false })
    NProgress.start()
    if (!window.existLoading) {
        loading.show()
        window.existLoading = true
    }
    next()
  })
  
export default router
  • 具体来说,在路由的全局前置守卫中进行版本检查,当触发路由跳转时,先执行版本检查的操作。
  • 如果是生产环境,判断是否已经有 version.js 文件,如果有,先删掉资源引入;然后创建一个<script>标签,并设置 src 值;页面中当前第一个 <script> 元素之前插入一个新的 <script>,从而加载并执行。
  • 通过这样的方式,能够及时地发现版本更新并实现页面的自动更新,提升用户体验和项目的维护便利性。
最终

执行 npm run build 命令行打包项目,最终dist文件夹里多了一个文件 version.js
此时版本号文件就生成了,并且每次打包后这个文件的内容都不一样。

在这里插入图片描述
在这里插入图片描述

最后 f12 查看 dom 结构,我们每次进入路由版本号因为是时间戳,所以都会更新。

在这里插入图片描述

注意事项
1) 报错

import pkg from '../../package.json' 时候,可能会有标红提示报错找不到模块“../../package.json”。请考虑使用 "--resolveJsonModule" 导入带 ".json" 扩展的模块

通常是因为在当前的 Node.js 环境中,默认不支持直接导入 .json 文件作为模块。如果在 TypeScript 项目中使用 import 导入 .json 文件,需要在 tsconfig.json 文件中启用 resolveJsonModule 选项,通过设置 “resolveJsonModule”: true,TypeScript 将会允许导入 .json 文件。

{
    "compilerOptions": {
        "resolveJsonModule": true,
        "esModuleInterop": true  // 如果需要的话,也需要启用这个选项
    }
}
2) window.getVersion

这是自定义的函数并将其绑定到 window 对象上,需要在项目中新建 types文件夹,新增一个global.d.ts 文件,写入下面代码,才不会标红提示。

interface Window {
    getVersion: Function
}

另外,如果我们想全局定义一个type类型,可直接在这个文件中定义,就可以全局使用该类型了,比如下面代码,

// 在 TypeScript 中非常有用,特别是当需要处理结构不固定、属性名称和类型不确定的对象时,对象里可以是任意类型,不受属性类型的严格限制
interface anyObj {
    [key: string]: any
}

可参考:
纯前端实现监控版本更新
vite实现前端项目打包更新通知用户更新
前端打包同时版本号自增
如何优雅的实现前端版本投产自动触发浏览器刷新更新版本内容

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙实现应用通知

目录&#xff1a; 1、应用通知的表现形式2、应用通知消息的实现1、发布普通文本类型通知2、发布进度类型通知3、更新通知4、移除通知 3、设置通知道通展示不同形式通知4、设置通知组5、为通知添加行为意图1、导入模块2、创建WantAgentInfo信息3、创建WantAgent对象4、构造Notif…

2024 年 MySQL 8.0.40 安装配置、Workbench汉化教程最简易(保姆级)

首先到官网上下载安装包&#xff1a;http://www.mysql.com 点击下载&#xff0c;拉到最下面&#xff0c;点击社区版下载 windows用户点击下面适用于windows的安装程序 点击下载&#xff0c;网络条件好可以点第一个&#xff0c;怕下着下着断了点第二个离线下载 双击下载好的安装…

【RabbitMQ】RabbitMQ中核心概念交换机(Exchange)、队列(Queue)和路由键(Routing Key)等详细介绍

博主介绍&#xff1a;✌全网粉丝21W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…

【C++笔记】AVL树的深度剖析

【C笔记】AVL树的深度剖析 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】AVL树的深度剖析前言一. AVL树的概念二.AVL树的实现2.1 AVL树的结构2.2 AVL树的插入2.3 平衡因子更新 三.旋转3.1旋转的原则3.2右单旋3.3左…

Ubuntu 环境安装 之 RabbitMQ 快速入手

Hi~&#xff01;这里是奋斗的明志&#xff0c;很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~~ &#x1f331;&#x1f331;个人主页&#xff1a;奋斗的明志 &#x1f331;&#x1f331;所属专栏&#xff1a;RabbitMQ &#x1f4da;本系列文章为个人学…

贪心算法专题(四)

目录 1. 单调递增的数字 1.1 算法原理 1.2 算法代码 2. 坏了的计算器 2.1 算法原理 2.2 算法代码 3. 合并区间 3.1 算法原理 3.2 算法代码 4. 无重叠区间 4.1 算法原理 4.2 算法代码 5. 用最少数量的箭引爆气球 5.1 算法原理 ​5.2 算法代码 1. 单调递增的数字…

IAR环境下的FlashLoader设计

目录 1.为什么要Flash Loader 2.Flash Loader设计细节 2.1 简单的代码框架 2.2 迷人的宏使用 2.3 关键的配置文件 3.dmac和mac文件 4.小结 搞国产车规芯片&#xff0c;IAR是必不可少的编译调试集成工具&#xff0c;历史背景不赘述&#xff0c;今天主要聊聊基于IAR的Fla…

一些硬件知识【2024/12/6】

MP6924A: 正点原子加热台拆解&#xff1a; PMOS 相比 NMOS 的缺点&#xff1a; 缺点描述迁移率低PMOS 中的空穴迁移率约为电子迁移率的 1/3 到 1/2&#xff0c;导致导通电流较低。开关速度慢由于迁移率较低&#xff0c;PMOS 的开关速度比 NMOS 慢&#xff0c;不适合高速数字电…

在本地运行大语言模型

1&#xff0c;打开下面网站下载&#xff0c;软件 lm studio 2&#xff0c; 设置模型下载路径 3&#xff0c;没有魔法条件的人&#xff0c;去镜像网站下载模型的镜像文件 、 4&#xff0c;

【单片机】ESP32-S3+多TMC2209控制步进电机系列3 使用TMC2209库实现UART通讯

目录 1.下载TMC2209.h库2.代码部分3.效果展示 1.下载TMC2209.h库 在Arudino环境中&#xff0c;有两个不错的库可以驱动TMC2209。 TMC2209库TMCStepper库 TMC2209库只针对TMC2209驱动器&#xff0c;而TMCStepper库除了能够支持TMC2209驱动器&#xff0c;还能够支持其他TMC的驱…

【服务器部署应用由http协议切换为https】

文章目录 服务器部署应用由http协议切换为https1. 下载openssl及其配置1.1 下载1.2 无脑下一步即可1.3 环境变量配置1.4 验证配置以及生成证书证书路径 2. nginx配置修改 服务器部署应用由http协议切换为https 1. 下载openssl及其配置 1.1 下载 openssl下载地址 根据系统选择…

Linux——管理用户和用户组

一、用户有哪些 root用户 定义&#xff1a;root用户是Linux系统中的最高权限用户&#xff0c;具有对系统所有资源的完全控制权。特性&#xff1a;root用户可以执行系统中的任何操作&#xff0c;包括修改系统配置文件、安装软件、管理系统服务等。由于其拥有最高权限&#xff0c…

synchronized的特性

1.互斥 对于synchronized修饰的方法及代码块不同线程想同时进行访问就会互斥。 就比如synchronized修饰代码块时&#xff0c;一个线程进入该代码块就会进行“加锁”。 退出代码块时会进行“解锁”。 当其他线程想要访问被加锁的代码块时&#xff0c;就会阻塞等待。 阻塞等待…

如何在树莓派上安装Arduino IDE

git clone https://github.com/JetsonHacksNano/installArduinoIDE.git cd installArduinoIDE ./installArduinoIDE.sh sudo reboot sudo shutdown -h now

【JAVA项目】基于ssm的【汽车在线销售系统】

【JAVA项目】基于ssm的【汽车在线销售系统】 技术简介&#xff1a;采用JSP技术、B/S架构、SSM框架、MySQL技术等实现。 系统简介&#xff1a;首页汽车在线销售系统模块如下&#xff1a;首页、汽车信息、新闻资讯、留言反馈、我的收藏管理等功能。管理员输入个人的账号、密码登录…

【代码随想录】刷题记录(66)-修剪二叉搜索树

题目描述&#xff1a; 给你二叉搜索树的根节点 root &#xff0c;同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即&#xff0c;如果没有被移除&#xff0c;原有的父…

《蓝桥杯比赛规划》

大家好啊&#xff01;我是NiJiMingCheng 我的博客&#xff1a;NiJiMingCheng 这节课我们来分享蓝桥杯比赛规划&#xff0c;好的规划会给我们的学习带来良好的收益&#xff0c;废话少说接下来就让我们进入学习规划吧&#xff0c;加油哦&#xff01;&#xff01;&#xff01; 一、…

Vue3+Vite项目从零搭建+安装依赖+配置按需导入

环境准备 Vscode/HBuilder等任何一种前端开发工具node.js&npm本地开发环境 源代码管理&#xff1a;Git 技术栈 项目构建 创建项目 npm create vite 依次运行最后三行出现&#xff0c;成功启动项目 在浏览器输入 http://localhost:5173/ 可以显示页面 src别名的配置…

小程序维护外包流程和费用

由于某些原因很多老板想要跟换掉小程序原来合作的开发公司&#xff0c;重新把小程序系统维护外包新的公司。小程序系统外包维护是一个涉及多个方面的过程&#xff0c;需要从需求明确、选择团队到持续优化等多个环节进行细致管理。以下就是小程序系统外包维护主要包括几个关键步…

Meta Llama 3.3 70B:性能卓越且成本效益的新选择

Meta Llama 3.3 70B&#xff1a;性能卓越且成本效益的新选择 引言 在人工智能领域&#xff0c;大型语言模型一直是研究和应用的热点。Meta公司最近发布了其最新的Llama系列模型——Llama 3.3 70B&#xff0c;这是一个具有70亿参数的生成式AI模型&#xff0c;它在性能上与4050…