前端实现发布版本,浏览器自动刷新

5,089 阅读2分钟

使用nodejs脚本生成版本信息json文件 + 监听页面显示和隐藏会触发的visibilitychange(页面显示和隐藏)事件(可以随意使用各种监听方式)

实现原理:

1、使用nodejs编写脚本,获取package.json版本信息,并保存为json文件,存放在构建打包的目录下(比如,public目录)

2、使用页面显示和隐藏会触发的visibilitychange事件,监听页面的显示和隐藏操作,如果页面显示,则请求打包放在dist根目录下的版本信息json文件,对比当前打包版本的version与历史版本信息json文件中version是否一致,如果不一致,则触发浏览器刷新

3、vite打包项目使用.env文件 + import.meta.env保存当前打包变量(webpack打包项目可以使用definePlugin插件 + process.env 保存变量)

1、使用nodejs编写获取package.json版本信息的脚本

import { execSync } from 'child_process'  // 子进程 execSync 要运行的命令
import fs from 'fs'
import dotenv from 'dotenv' // .env文件中加载环境变量 然后将这些环境变量加载到process.env对象中
import dayjs from 'dayjs'

/** 定义模块和变量**/

const versionInfoPath = 'versionInfo.json' // versionInfo路径
const pagePath = 'package.json'
const publicPath = 'public' // 不能放到dist目录(该目录打包文件会被清空),要放到public目录,
const autoPush = false // 写入版本信息之后是否自动提交git上
const isVite = true // 是否是vite构建打包
let pageInfo = {}


let versionInfoObj = {} // 保存git版本信息


// 如果versionInfoPath存在,将先读取里边的版本信息
if (fs.existsSync(versionInfoPath)) {
  versionInfoObj = JSON.parse(fs.readFileSync(versionInfoPath).toString())
}
// 获取package.pack 的版本号
if (fs.existsSync(pagePath)) {
  pageInfo = JSON.parse(fs.readFileSync(pagePath).toString())
}

// 判断当前版本是否已经存在,存在则不再次生成
if (pageInfo && versionInfoObj.version === pageInfo.version) {
  console.warn('\x1B[33m%s\x1b[0m', 'warning: 当前的git版本数据已经存在了!\n')
} else {

  versionInfoObj = {
    version: pageInfo.version,
    name: pageInfo.name,
    date: dayjs().format('YYYY-MM-DD HH:mm:ss'),
  }
  const saveInfoStr = JSON.stringify(versionInfoObj, null, 2)
  fs.writeFileSync(versionInfoPath, saveInfoStr)

  // 程序执行结束
  console.log(
    '\x1b[32m%s\x1b[0m',
    `execute success: file address is ${process.cwd()}/${versionInfoPath}\n`,
  )
}

// 将versionInfo文件移植到public文件中,以便构建工具能够正常打包到项目根目录
if (fs.existsSync(publicPath)) {
  fs.writeFileSync(
    `${process.cwd()}/${publicPath}/${versionInfoPath}`,
    fs.readFileSync(versionInfoPath),
  )
}

// 如果是vite构建打包,把git信息追加写入.env文件中
if (isVite) {
  // const dotenv = require('dotenv')

  const envPath = `${process.cwd()}/.env`
  // 读取 .env 文件内容
  const envContent = fs.readFileSync(envPath, {
    encoding: 'utf-8',
  })

  // 解析内容为键值对对象
  const envVariables = dotenv.parse(envContent)
  const versionInfoStr = JSON.stringify(versionInfoObj)
  // 修改特定的环境变量
  envVariables.VITE_GIT_INFO = versionInfoStr

  // 将修改后的键值对转换为字符串
  const updatedEnvContent = Object.entries(envVariables)
    .map(([key, value]) => `${key}=${value}`)
    .join('\n')

  // 将修改后的内容写入 .env 文件
  console.log(updatedEnvContent)
  fs.writeFileSync(envPath, updatedEnvContent, { encoding: 'utf-8' })

  console.log('\x1b[32m%s\x1b[0m', '.env 文件已更新')
}

2、配置执行获取git版本信息脚本命令

// package.json

"scripts": {
   "build:git": "npm run get-git && vite build",
    "get-git": "node scripts/useNodeGetGitInfo.js",
},

3、项目入口JS文件,监听visibilitychange事件

 // 检测新版本自动刷新浏览器更新版本内容
  const gitInfo = import.meta.env.VITE_GIT_INFO
  const gitInfoObj = gitInfo && JSON.parse(gitInfo)
  if (document.visibilityState === 'hidden') return
  fetch(`/versionInfo.json?v=${Date.now()}`)
    .then((res) => {
      return res.json()
    })
    .then((data) => {
      // 版本不一致,可自动更新,或者提示弹框,让用户刷新,自行判断
      if (data.version !== gitInfoObj.version) {
        location.reload()
      }
    })