实现页面自动检测更新(不动服务端代码)

今天分享一个实现页面自动检测更新,而且不需要动服务端代码的方法,比较取巧,在非覆盖式发布的情况下可以简单使用。

背景和思路

有部分运营是不刷新页面的,当我们前端资源更新了,他可能还在使用老的资源。

目标是希望在我们前端资源更新的时候提示用户有资源更新,然后刷新页面获取最新的前端资源。

一个适合非覆盖式发布的前端应用的自动检测更新方法。

覆盖式发布

前后两次发布的资源没有差异,js 资源也不使用 hash 进行区分

非覆盖式发布

前后两次发布的资源会有差异,比如体现在 js 资源带上 hash 或者发布的版本号

所以,我们以构建之后 js 资源带 hash 的页面为例,如果有新的发布,那么 js 资源的链接就会发生改变,通过比较前后两次的资源地址来判断页面是否发布。


构建之后是带 hash 的资源文件

代码

export const DEYAL_UPDATE_INTERVAL = 30 * 1000; // 30 秒

let initJsUrls: string[] = [];

// 获取 html
export async function fetchHtml(
  url: string,
  fetcher = window.fetch
): Promise {
  try {
    const res = await fetcher(url);
    return res.text();
  } catch (error) {
    console.error(error);
    return "";
  }
}

// 提取 HTML 中所有 js 的地址
export function extractJsUrls(html: string): string[] {
  const regex = /<script.*?src="(.*?)"/g;
  const matches = [...html.matchAll(regex)];
  return matches.map((match) => match[1]);
}

export async function needUpdate(targetUrl: string) {
  const html = await fetchHtml(targetUrl);
  let result = false;
  if (html) {
    const newJsUrls = extractJsUrls(html);
    console.log(initJsUrls, newJsUrls);

    if (initJsUrls.length != newJsUrls.length) {
      result = true;
    }

    for (let i = 0; i < newjsurls.length i if newjsurlsi result='true;' break if initjsurls.length result='false;' initjsurls='newJsUrls;' return result export function autoupdate url: string duration: number='DEYAL_UPDATE_INTERVAL' settimeoutasync> {
    const willUpdate = await needUpdate(url);

    if (willUpdate) {
      const result = confirm("检测到新版本,是否更新?");
      if (result) {
        window.location.reload();
      }
    }

    autoUpdate(url, duration);
  }, duration);
}