前端发版更新提示(不需要后端)

2,465 阅读3分钟

概述

  1. 前端工程在打包发布之后,用户并不知道我们前端发版了,甚至根本不知道前端发版之后,怎么获取前端的最新版本,这样会造成很多因为前端没有更新所造成的功能不全,或者按照上一版本的数据提交给后端,造成数据错误的bug。
  2. 既然是前端版本的更新,那就是我们前端开发工程师的工作,是否能够不需要后端开发来些个接口,甚至还要建个新表或者往哪个倒霉的表里塞一条数据,然后不知道哪天哪个倒霉的后端就把数据删除了,然后报错。
  3. 首先前端版本得要有个放版本信息的地方,这个地方要在我们发版后必须通过网络请求来获取,还要在我们发版的时候去维护一下他;我最开始做的一版是通过数据字典来存放,我每发版一次,需要去数据字典中维护一次,但不是每个前端工程都有数据字典这个东西的;于是就重新找地方存放版本信息,想了半天,最终放在工程目录的 public 目录下,这个目录打包之后会被丢到 dist 目录下,然后部署到服务器之后,我们可以通过网络请求获取到这个目录下的文件,再把它弄成 json 文件,直接可以进行 json 序列化获取数据,剩下的就是开发了;

目录

上代码

  1. 将模块单独抽成一个 version.js 文件

    import axios from "axios";
    import {
      MessageBox,
    } from 'element-ui'
    let interval = null
    // 记录当前时间并转成时间戳
    const NOW = new Date().getTime();
    // 轮询间隔时间,分钟为单位
    const MINUTE = 30
    
    // 从缓存中获取用户上次退出的时间戳
    const LEAVE_TIME = parseInt(localStorage.getItem('LEAVE_TIME'), 10);
    // 判断是否为刷新,两次间隔在5s内判定为刷新操作
    (!LEAVE_TIME || (NOW - LEAVE_TIME) <= 5 * 1000) && localStorage.removeItem('version')
    
    // 退出当前页面执行
    window.onunload = () => {
      localStorage.setItem("LEAVE_TIME", new Date().getTime());
    };
    
    setTimeout(() => checkUpdate(), 1 * 1000)
    // 开启计时器
    openInterval();
    
    function openInterval() {
      interval = setInterval(() => checkUpdate(), MINUTE * 60 * 1000);
    }
    
    function checkUpdate() {
      // 使用 axios,不走响应拦截
      axios({
        url: location.origin + "/version.json"
      }).then((res) => {
        if (res.data && res.data.version) {
          let version = localStorage.getItem("version");
          // 本地没有 version,表示刚进入系统,直接塞值
          if (!version) return localStorage.setItem("version", res.data.version);
    
          if (res.data.version != version) {
            // 如果本地 version 跟获取的 version 不一致,则把最新的 version 保存本地,并重新加载页面
            clearInterval(interval); // 有弹窗,则清除轮询
            MessageBox.confirm("发现新版本, 是否更新?", "提示", {
                closeOnClickModal: false,
                closeOnPressEscape: false,
                showClose: false,
                confirmButtonText: "更新",
                cancelButtonText: `${MINUTE}分钟后提醒我`,
                type: "warning",
              })
              .then(() => {
                localStorage.setItem('version', res.data.version)
                location.reload();
              })
              .catch(() => openInterval());
          }
        }
        // 404 未找到该 JSON 文件,则停止轮询
      }).catch(err => err.toString().indexOf('404') > -1 && clearInterval(interval));
    }
    
  2. 然后在 main.js 中引入该 js 文件,会直接运行;

继续追加功能,打包自动更新 version.json 里面的版本信息

  1. 上述功能完成后,版本更新就能用了,但是每次发版的时候,我们都需要去手动改 version.json 文件,麻烦,那能不能省掉这个步骤呢,当然可以;

  2. 想一下打包的过程,不就是将我们写的代码打包到 dist 目录下吗,dist 下面的所有文件都是通过 node 模块自动生成的,那自动修改 version.json 肯定也可以;

  3. 上代码:在 vue.config.js 文件中

        /**
         * 通过 node 的 fs 模块对静态文件进行修改
         */
        // 开发环境不走逻辑,具体怎么判断,开发者自己定
        if (process.env.ENV !== "development") {
          const fs = require("fs");
          // 异步读取 version.json 文件
          fs.readFile("./public/version.json", "utf8", (err, data) => {
            if (!err) {
              let obj
              try {
                obj = JSON.parse(data)
                obj.version++
              } catch (error) {
                throw Error(error)
              }
              // 在 JSON 序列化成功才会去同步修改 version.json 文件内容
              if (obj) fs.writeFileSync("./public/version.json", JSON.stringify(obj))
              // 没有找到文件,抛出异常
            } else throw Error(err)
          })
        }