vite实现前端项目打包更新通知用户更新

2,215 阅读3分钟

在前端项目中,为了实现对版本迭代更新的监控以及页面的自动更新,我们可以采取一系列巧妙的措施。首先,需要禁止浏览器对索引页面(index.html)和版本信息文件(version.json)进行缓存。

为此,我们可以在 Nginx 中进行不缓存处理,通过添加相应的配置来实现,即当遇到以.htm、.html 或.json 结尾的文件请求时,设置其过期时间为-1。

location ~ .*.(htm|html|json)?$ {
    expires -1;
}

接下来,利用 Vite 插件在打包生产代码时自动生成版本信息。我们创建一个版本信息插件,其中包含了相关的处理逻辑。当进行构建开始时,会生成版本信息文件的路径。

这里我们以编译时间作为版本信息,将其转换为 JSON 格式的内容。如果公共目录存在,就直接写入版本信息文件;若不存在,则先创建公共目录,再进行写入操作。

在项目根目录新建一个plugin来存放vite的插件,创建一个versionUpdatePlugin.js来编写打包更新插件

image.png

// versionUpdatePlugin.js
const fs = require('fs')
const path = require('path')

const writeVersion = (versionFile, content) => {
  // 通过fs模块写入文件
  fs.writeFile(versionFile, content, (err) => {
    if (err) throw err
  })
}

export default (options) => {
  let config

  return {
    name: 'version-update',

    configResolved(resolvedConfig) {
      // 存储最终解析的配置
      config = resolvedConfig
    },

    buildStart() {
      // 生成版本信息文件路径存到dist的version.json
      const file = config.publicDir + path.sep + 'version.json'
      // 这里使用编译时间作为版本信息
      const content = JSON.stringify({ version: options.version })

      if (fs.existsSync(config.publicDir)) {
        writeVersion(file, content)
      } else {
        fs.mkdir(config.publicDir, (err) => {
          if (err) throw err
          writeVersion(file, content)
        })
      }
    },
  }
}

在 Vite 配置文件中,定义一个全局变量来表示当前应用的版本,其值为当前的时间戳。同时,在插件配置中加入我们自定义的版本信息插件,并传递相应的版本信息。

// vite.config.js
export default defineConfig((config) => {
// 获取当前的时间
  const now = new Date().getTime()
  return {
    ...
    define: {
      // 定义全局变量
      __APP_VERSION__: now,
    },
    plugins: [
      ...
      versionUpdatePlugin({
        version: now,
      }),
    ],
    ...
  }
})

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

// 路由拦截
router.beforeEach((to, from, next) => {
  checkUpdate()
  next()
}
  • 具体来说,在路由的全局前置守卫中进行版本检查,当触发路由跳转时,先执行版本检查的操作
  • 如果处于开发环境则直接跳过,否则通过发送请求获取服务器端的版本信息。
  • 若本地的版本与服务器端的版本不一致,就弹出一个提示消息,告知用户发现新内容并正在自动更新。
  • 消息显示一定时间后关闭,关闭时进行页面的重新加载以获取新的索引页面。
  • 通过这样的方式,能够及时地发现版本更新并实现页面的自动更新,提升用户体验和项目的维护便利性。
function checkUpdate() {
  if (import.meta.env.DEV) return
  axios.get('/version.json').then((res) => {
    if (__APP_VERSION__ !== res.data.version) {
      MessageBox.confirm('检测到版本更新,请刷新页面!!', '版本升级提示', {
        type: 'warning',
        showClose: false,
        showCancelButton: false,
        closeOnClickModal: false,
        closeOnPressEscape: false
      })
        .then(() => {
          router.go(0)
        })
        .catch(() => {})
    }
  })
}

最终效果

image.png

当然实现的方式有很多,这里只是其中一种比较常见的做法,相对来说是比较简单

下面是其他方式,可以了解一下

方式一:使用 Service Worker

  1. 在 Service Worker 中监听 fetch 事件,当请求特定资源(如版本信息文件)时进行版本比较。
  2. 如果版本有更新,通过 postMessage 等方式通知页面进行更新操作。

方式二:利用消息队列机制

  1. 服务端在有更新时向特定的消息队列发送更新消息。
  2. 前端通过订阅该消息队列来获取更新通知,并执行相应的更新流程。

方式三:基于 WebSocket 长连接

  1. 建立前端与服务端的 WebSocket 连接。
  2. 服务端主动推送更新信息到前端。