vue3+vite纯前端实现自动触发欣赏器刷新更新版本内容,并在打包时生成版本 ...

种地  金牌会员 | 2024-8-21 03:32:49 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 554|帖子 554|积分 1662

媒介

在前端项目中,有时间为了实现自动触发欣赏器刷新并更新版本内容,可以采取一系列巧妙的步伐。我的项目中是必要在打包时间生成一个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() 方法用于异步地将数据写入文件。其基本语法如下:
  1. 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文件
  1. // build.ts
  2. import pkg from '../../package.json'
  3. import { resolve } from 'path'
  4. import fs from 'fs'
  5. const version = new Date().getTime()
  6. const content = `getVersion(${version})`
  7. // 创建版本文件
  8. fs.writeFile(`${resolve(__dirname, '../../dist')}/version.js`, content, (err) => (err ? console.log(err) : console.log('版本文件创建成功')))
  9. export const run = () => {
  10.   console.log(`${pkg.name} - build successfully!`)
  11. }
复制代码
假如上面这种node提示报错的话,可替换为下面这种
  1. import pkg from '../../package.json'
  2. import fs from 'fs'
  3. import { fileURLToPath, URL } from 'node:url'
  4. const version = new Date().getTime()
  5. const content = `getVersion(${version})`
  6. // 创建版本文件
  7. fs.writeFile(fileURLToPath(new URL('../../dist/version.js', import.meta.url)), content, (err) =>
  8.     err ? console.log(err) : console.log('版本文件创建成功')
  9. )
  10. export const run = () => {
  11.     console.log(`✨ ${pkg.name} - build successfully!`)
  12. }
  13. run()
复制代码
在package.json文件中配置执行 npm run build 时执行的任务

在package.json的build下令上加一行执行 esno ./src/utils/build.ts
  1. {
  2.    "name": "ceshi",
  3.    "version": "1.0.0",
  4.    "scripts": {
  5.       "dev": "vite --force",
  6.       "build": "vite build && esno ./src/utils/build.ts"
  7.     }
  8. }
复制代码
创建 version.ts 文件

src/utils/文件夹下创建 version.ts文件
  1. import Cookies from 'js-cookie'
  2. import { ElLoading } from 'element-plus'
  3. const versionKey = 'version-id'
  4. export function getVersionId() {
  5.     return Cookies.get(versionKey) ? Number(Cookies.get(versionKey)) : 0
  6. }
  7. export function setVersionId(version: number) {
  8.     return Cookies.set(versionKey, String(version))
  9. }
  10. export function removeVersionId(version: number) {
  11.     Cookies.remove(versionKey)
  12. }
  13. export function handleVersion() {
  14.     if (process.env.NODE_ENV !== 'development') {
  15.         window.getVersion = (version: number) => {
  16.             if (!getVersionId() || (getVersionId() * 1 && version * 1 !== getVersionId() * 1)) {
  17.                 ElLoading.service() // 启动全屏ElLoading
  18.                 location.reload() // 刷新页面
  19.             }
  20.             setVersionId(version) // 保存 以便下次使用判断
  21.         }
  22.     }
  23. }
  24. export function insertVersionFile() {
  25.     if (process.env.NODE_ENV !== 'development') {
  26.         const scriptCollection = document.getElementsByTagName('script')
  27.         // 判断是否已经有version.js 文件,如果有,先删掉资源引入
  28.         // const scriptAry =[...scriptCollection] // ie不支持这种写法(HTMLCollection 不是数组)
  29.         const scriptAry = Array.from(scriptCollection)
  30.         scriptAry.some((v) => {
  31.             const flag = v.src.indexOf('version.js') !== -1
  32.             if (flag) {
  33.                 v.parentNode?.removeChild(v)
  34.             }
  35.             return flag
  36.         })
  37.         const versionScript = document.createElement('script')
  38.         versionScript.src = import.meta.env.VITE_BASE_PATH + 'version.js?v=' + new Date().getTime()
  39.         //document.getElementsByTagName('script')表示返回当前页面中所有 <script> 元素的集合
  40.         const s = document.getElementsByTagName('script')[0]  
  41.         s.parentNode?.insertBefore(versionScript, s)
  42.     }
  43. }
  44. handleVersion()
复制代码
router =》index.ts 中在前置路由,插入而且查抄版本号

在路由跳转时进行实时的版本检测,本质就是在路由拦截器去做这个操纵。
  1. import { insertVersionFile } from '/@/utils/version'
  2. const router = createRouter({
  3.     history: createWebHashHistory(),
  4.     routes: staticRoutes,
  5. })
  6. router.beforeEach((to, from, next) => {
  7.     // 插入并且检查版本号
  8.     insertVersionFile()
  9.     NProgress.configure({ showSpinner: false })
  10.     NProgress.start()
  11.     if (!window.existLoading) {
  12.         loading.show()
  13.         window.existLoading = true
  14.     }
  15.     next()
  16.   })
  17.   
  18. 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 文件。
  1. {
  2.     "compilerOptions": {
  3.         "resolveJsonModule": true,
  4.         "esModuleInterop": true  // 如果需要的话,也需要启用这个选项
  5.     }
  6. }
复制代码
2) window.getVersion

这是自界说的函数并将其绑定到 window 对象上,必要在项目中新建 types文件夹,新增一个global.d.ts 文件,写入下面代码,才不会标红提示。
  1. interface Window {
  2.     getVersion: Function
  3. }
复制代码
别的,假如我们想全局界说一个type范例,可直接在这个文件中界说,就可以全局利用该范例了,比如下面代码,
  1. // 在 TypeScript 中非常有用,特别是当需要处理结构不固定、属性名称和类型不确定的对象时,对象里可以是任意类型,不受属性类型的严格限制
  2. interface anyObj {
  3.     [key: string]: any
  4. }
复制代码
可参考:
纯前端实现监控版本更新
vite实现前端项目打包更新通知用户更新
前端打包同时版本号自增
如何优雅的实现前端版本投产自动触发欣赏器刷新更新版本内容

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

种地

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表