美文网首页
Vue3+vite前端项目打包升级发版后,不手动刷新,页面跳转文

Vue3+vite前端项目打包升级发版后,不手动刷新,页面跳转文

作者: xikoo0 | 来源:发表于2023-08-17 18:00 被阅读0次

    产生原因:

    使用vite对项目进行打包,对 js 和 css 文件使用了 chunkhash 进行了文件缓存控制,但是项目的index.html文件在版本频繁迭代更新时,会存在被浏览器缓存的情况。
    在发版后,如果用户不强制刷新页面,浏览器会使用旧的index.html文件,在跳转页面时会向服务器端请求了上个版本 chunkhash 的 js 和 css 文件,但此时的文件已经在版本更新时已替换删除了,最终表现为页面卡顿,控制台报错 404。

    解决方案:

    方案1

    服务器发版时,上一个版本的asset文件包不删除
    缺点:随着频繁发版,服务器端前端项目文件会越来越多,浪费空间;若旧页面的接口涉及到参数改动等,会引起报错;流水线使用 docker 打包部署会变得非常麻烦。

    方案2:

    在每一次打包时,前端生成一个version版本号,路由跳转时请求服务端的version.json数据,与本地缓存的版本号做对比,从而监控版本迭代变化,实现自动更新。
    缺点:在实现自动更新的过程,没办法跳到指定的页面,需要刷新后再重新点击。但这个体验感可以忽略不计。

    具体操作步骤如下:

    1. 在项目目录下创建build文件
    // build\build.js
    console.log("build > 文件开始执行!")
    const fs = require("fs")
    const path = require("path")
    
    function getRootPath(...dir) {
      return path.resolve(process.cwd(), ...dir)
    }
    const runBuild = async () => {
      try {
        const OUTPUT_DIR = "dist"
        const VERSION = "version.json"
        const versionJson = {
          version: "V_" + Math.floor(Math.random() * 10000) + Date.now()
        }
        fs.writeFileSync(getRootPath(`${OUTPUT_DIR}/${VERSION}`), JSON.stringify(versionJson))
        console.log(`version file is build successfully!`)
      } catch (error) {
        console.error("version build error:\n" + error)
        process.exit(1)
      }
    }
    runBuild()
    console.log("build > 文件执行结束!")
    
    1. package.json中配置"postbuild": "node ./build/build.js",不同环境的构建都要配置
     "postbuild": "node ./build/build.js",
     "postbuild:test": "node ./build/build.js",
     "postbuild:pre": "node ./build/build.js",
    
    1. 封装本地缓存版本号的读写方法
    export const getAppVersion = () => {
      return localStorage.getItem(CacheKey.APP_VERSION) as string
    }
    export const setAppVersion = (version: string) => {
      localStorage.setItem(CacheKey.APP_VERSION, version)
    }
    
    1. 写一个公共方法,用于检验服务端版本号是否更新,如有更新则自动刷新
    // 检查服务端是否已经更新,如果更新刷新页面
    export async function checkAppNewVersion() {
      if (process.env.NODE_ENV === "development") {
        return
      }
    // 带参数是为了拿到最新的数据
      const url = `/version.json?t=${Date.now()}`
      let res = null
      try {
        res = await axios.get(url)
      } catch (err) {
        console.error("checkAppNewVersion error: ", err)
      }
      if (!res) return
      const version = res.data.version
      const localVersion = getAppVersion()
      if (localVersion && localVersion == version) {
        return
      }
      if (localVersion && localVersion !== version) {
        ElMessage({
          message: "发现新内容,自动更新中...",
          type: "success",
          showClose: true,
          duration: 1500,
          onClose: () => {
            setAppVersion(version)
            window.location.reload()
          }
        })
      }
      setAppVersion(version)
    }
    
    1. router.beforeEach钩子中,请求服务器version版本号
    router.beforeEach(async (to, _from, next) => {
      await checkAppNewVersion()
      ...
      })
    
    1. 为了防止当用户在登录页时,服务端更新了版本,所以用户在输入用户名和密码之后,点击登录,显示登录成功,正常是应该直接跳到首页,但是此时跳转前检测到版本更新,所以会原地刷新一下获取最新资源,导致页面又恢复到了登录之前的状态,用户需要重新登录。可以在App.vue中加入这个监听
    // 监听页面打开显示
    document.addEventListener('visibilitychange', function () {
      // console.log('show ===>', document.visibilityState, !document.hidden)
      if (!document.hidden) {
        checkAppNewVersion()
      }
    })
    
    

    注意:

    如果是采用pnpm打包,需要在.npmrc中配置:

    enable-pre-post-scripts=true
    

    相关文章

      网友评论

          本文标题:Vue3+vite前端项目打包升级发版后,不手动刷新,页面跳转文

          本文链接:https://www.haomeiwen.com/subject/jcrrmdtx.html