分享一个只有5KB大的检测项目版本并自动刷新的小工具

82 阅读3分钟

关于手写一个检查vue项目部署到服务器之后,用户在浏览器自动检查版本并刷新的小工具

背景:在开发前端项目时,将项目打包部署到服务器上以后,如果用户没有手动刷新浏览器或者重新进入网站,是无法看到更新的内容的。以此,我决定用js写个脚本来自动检测版本。

工具暂时只在vue项目上试过

我的设计思路首先是先将版本号存在sessionStorage中,为啥放在sessionStorage中呢?因为sessionStorage有个好处,页面关闭就会被清空,所以只用关注页面打开时版本更新问题。用户第一次在浏览器上打开页面,我们将项目的版本号存放在sessionStorage中,然后可以选择触发时机可以选择路由的前置守卫或者请求工具的拦截中去触发检测版本的事件。核心思路确定了,然后就可以写代码了。
  1. 使用XMLHttpRequest去获取页面的index.html内容字符串
/**
 * 请求html页面内容
 * @param { Function }  callback 回调函数

 */
const getPage = callback => {
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
      if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
        const res = xhr.response
          .match(/version:(?:(?!<\/p>).|\n)*?"/gm)[0]
          .split("version:")[1];
        const version = res.substring(0, res.length - 1);
        callback(version);
      }
    }
  };
  xhr.open("get", window.location.host, true);
  xhr.send(null);
};

2.创建一个弹窗,询问用户版本更新,是否刷新

1677336971454_DC629E6A-9D17-44b2-9D4F-4A05AE107F35.png

/**
 * 弹出对话框,询问是否刷新浏览器
 */
const dialogAsk = () => {
  if (dialog) return;
  let div = document.createElement("div");
  div.setAttribute(
    "style",
    "padding: 24px 15px;border: 1px solid #eee;border-radius: 4px;position: fixed;top: 2%;left: 50%;background-color: #fff;z-index:9999999;opacity: 0;transform: translate(-50%, -200%);transition: .5s ease;"
  );
  div.setAttribute("id", "dialog-version-ask");
  div.innerHTML = `检测到有版本更新,选择<a href=javascript:;() " style="color:#409eff;text-decoration:underline;">立即刷新</a> ,<a style="color:#409eff;text-decoration:underline;" href=javascript:;() >暂不提示</a> `;
  Array.from(div.children).forEach((ele, index) => {
    if (index < 2) {
      ele.addEventListener("click", () => {
        if (index === 0) {
          no_check = true;
          window.location.reload(true);
        } else {
          version_get_set({
            ...version_get_set("get"),
            noCheck: true
          });
          showHide(0);
        }
      });
    }
  });
  document.body.appendChild(div);
  dialog = document.getElementById("dialog-version-ask");
};

3.控制弹窗显示隐藏

@param { Boolean } visible

const showHide = visible => { if (dialog) { dialog.style.opacity = visible; dialog.style.transform = "translate(-50%, " + (visible ? 0 : -200) + "%)"; } };

4.获取储存在sessionStorage中的版本信息

    /**
 * 获取存储在cookies中的版本号信息
 * @param { {timeStamp:String,version:String,noCheck:Boolean}|String } data
 * @return { {}|{timeStamp:String,version:String,noCheck:Boolean}|undefined }
 */
const version_get_set = data => {
  if (Object.prototype.toString.call(data) === "[object Object]") {
    sessionStorage.setItem(key, JSON.stringify(data));
  } else {
    return sessionStorage.getItem(key)
      ? JSON.parse(sessionStorage.getItem(key))
      : {};
  }
};

5.判断是否检查版本号

    /**
 * 判断是否执行检查版本号
 * @param { Function } callback 回调事件
 * @param { String } env 项目编译环境
 * @param { String } env_key 项目开发环境名称
 */
const whetherCheck = (env, env_key, callback) => {
  if (env === env_key) return;
  browserLoad();
  const session_version = version_get_set("get");
  if (session_version["noCheck"]) return;
  if (JSON.stringify(session_version) === "{}") {
    callback();
    dialogAsk();
  } else if (Date.now() - session_version.timeStamp >=300000) {
    callback();
    dialogAsk();
  }
};

6.浏览器刷新事件,更新存储在session里的版本数据

    /**
 * 检测浏览器刷新和关闭事件
 * @return { Function }
 */
    const browserLoad = () => {
  if (Object.prototype.toString.call(window.onload) === "[object Function]")
    return;
  window.onload = () => {
    no_check = true;
    if (timer_2) {
      clearTimeout(timer_2)
      timer_2 = null
    }
   timer_2 = setTimeout(() => {
      no_check = false;
      clearTimeout(timer_2)
      timer_2 = null
    }, 3000);
    getPage(version => {
      const session_version = version_get_set("get");
      version_get_set({
        ...session_version,
        timeStamp: Date.now(),
        version: version
      });
    });
  };
};

7.最后一步,也就是最主要的一步,检查版本号

    /**
 * 检查版本号,并自动刷新
 */
export function checkVersion(env, env_key) {
  whetherCheck(env, env_key, () => {
    getPage(version => {
      if (timer_1) {
        clearTimeout(timer_1)
        timer_1 = null
      }
     timer_1 = setTimeout(() => {
        if (no_check) return;
        const session_version = version_get_set("get");
        if (session_version.version === version)
          version_get_set({ ...session_version, timeStamp: Date.now() });
        if (session_version.version !== version) showHide(1);
        clearTimeout(timer_1)
        timer_1 = null
      }, 777);
    });
  });
}

-补充:

在路由前置守卫中执行

2.png

每次打包前需要在index.html内如下一样去补充版本号

屏幕截图 2023-02-25 234152.png

以上就是全部代码,基本可以实现在每次路由变化或者调接口时去检查版本,并提醒刷新。如果各位觉得我做得不够好或者有得改进的地方欢迎私信我!码云仓库地址:gitee.com/knakn/check…

最后的最后,贴一个全部代码图: