前端发布项目自动更新

思路:无论vue还是react打包都会有dist文件夹,内部有index.html。我是想根据index.html中的script src地址是否改变,判断项目是否有新内容。

具体代码如下

首先先拿到生产环境中index.html文本,由于是单页面应用使用fetch('/?_stamp='+Date.now())来拿到html文本。并获取所有的src地址。

const scriptReg = /\<script.*src=["'](?<src>[^"']+)/gm;

async function getScriptSrcs() {
  const html = await fetch('/?_timestamp=' + Date.now()).then((res) =>
    res.text(),
  );
  scriptReg.lastIndex = 0;
  let result = [];
  let match;
  while ((match = scriptReg.exec(html))) {
    result.push(match.groups.src);
  }

  return result;
}

全局定义lastSrcs表示旧的地址数组,然后和新的newScripts对比,如果长度不同或者某一项不同则表示项目有新内容更新。

async function needUpdate() {
  const newScripts = await getScriptSrcs();

  if (!lastSrcs) {
    lastSrcs = newScripts;
    return false;
  }
  let result = false;
  if (lastSrcs.length !== newScripts.length) {
    result = true;
  }
  for (let i = 0; i < lastSrcs.length; i++) {
    if (lastSrcs[i] !== newScripts[i]) {
      result = true;
      break;
    }
  }
  lastSrcs = newScripts;
  return result;
}

最终我们使用轮询的方式监听是否变化。

const autoRefresh=()=>{
    setTimeout(async()=>{
        const willUpdate = await needUpdate();
         if (willUpdate) {
          const result = confirm('页面有更新,请刷新页面');
         if (result) {
            location.reload();
          }
        }
        autoRefresh();
    },5000);
}

最后在main.ts中引入即可。有什么问题私信哦。

后续:我想加一个可以自动关闭的功能,但是使用window.confirm我无法实现,尝试使用alert也无法成功,然后就想到是不是可以重写这个alert,结果发现果然可以。代码如下:直接复制即可使用,需要在入口文件引入。

let lastSrcs;
let timeoutId: any = 0;
let strHtml,
  time = 5,
  timer = null,
  timer1 = null;
const scriptReg = /\<script.*src=["'](?<src>[^"']+)/gm;

async function getScriptSrcs() {
  const html = await fetch('/?_timestamp=' + Date.now()).then((res) =>
    res.text(),
  );
  scriptReg.lastIndex = 0;
  let result = [];
  let match;
  while ((match = scriptReg.exec(html))) {
    result.push(match.groups.src);
  }

  return result;
}
async function needUpdate() {
  const newScripts = await getScriptSrcs();

  if (!lastSrcs) {
    lastSrcs = newScripts;
    return false;
  }
  let result = false;
  if (lastSrcs.length !== newScripts.length) {
    result = true;
  }
  for (let i = 0; i < lastSrcs.length; i++) {
    if (lastSrcs[i] !== newScripts[i]) {
      result = true;
      break;
    }
  }
  lastSrcs = newScripts;
  return result;
}

function createMask() {
  var shield = document.createElement('DIV');
  shield.id = 'shield';
  shield.style.position = 'absolute';
  shield.style.left = '0px';
  shield.style.top = '0px';
  shield.style.width = '100%';
  shield.style.height = document.body.scrollHeight + 'px';
  shield.style.background = 'transparent';
  shield.style.textAlign = 'center';
  shield.style.zIndex = '10000';
  shield.style.filter = 'alpha(opacity=0)';
  document.body.appendChild(shield);
  return shield;
}

function createAlert(txt) {
  var alertFram = document.createElement('DIV');
  alertFram.id = 'alertFram';
  alertFram.style.position = 'absolute';
  alertFram.style.left = '50%';
  alertFram.style.top = '0';
  alertFram.style.background = '#fff';
  alertFram.style.transform = 'translateX(-50%)';
  alertFram.style.width = '450px';
  alertFram.style.height = '150px';
  alertFram.style.textAlign = 'center';
  alertFram.style.lineHeight = '150px';
  alertFram.style.zIndex = '10001';

  strHtml =
    '<ul style="list-style:none;margin:0px;padding:0px;width:100%;border-radius:10px;overflow:hidden;box-shadow:0 0 5px 5px #ccc">\n';
  strHtml +=
    ' <li style="background:#1677ff;text-align:left;padding-left:20px;font-size:14px;font-weight:bold;height:40px;line-height:40px;color:#fff">系统提示</li>\n';
  strHtml +=
    '<li id="_content" style="background:#fff;text-align:center;font-size:14px;height:100px;line-height:100px;">' +
    txt +
    '</li>\n';
  strHtml += `<li style="background:#fff;text-align:right;font-weight:bold;height:50px;line-height:25px;padding-bottom:10px ;padding-right:20px;"><input type="button" id="_btn_click" style="outline:none;cursor:pointer;border:0;width:70px;height:40px;border-radius:20px;background:#1677ff;color:#fff" value="确 定"/></li>\n`;
  strHtml += '</ul>\n';
  alertFram.innerHTML = strHtml;
  document.body.appendChild(alertFram);
  return alertFram;
}

function removerDom(alertFram, mask) {
  document.body.removeChild(alertFram);
  document.body.removeChild(mask);
  window.location.reload();
}

function controlTime(alertFram, mask) {
  timer1 = setInterval(() => {
    time -= 1;
    document.getElementById('_content').textContent =
      `页面有更新,${time}秒后将强制刷新页面!`;
    if (time === 0) {
      clearTimeout(timer1);
      removerDom(alertFram, mask);
    }
  }, 1000);
}

window.alert = function (txt) {
  const alertFram = createAlert(txt);
  const mask = createMask();
  controlTime(alertFram, mask);
  const dom = document.getElementById('_btn_click');
  dom.onclick = () => {
    removerDom(alertFram, mask);
  };
};

const duration = 5000;

function autoRefresh() {
  timer = setTimeout(async () => {
    const willUpdate = await needUpdate();
    let content = `页面有更新,${time}秒后将强制刷新页面!`;
    if (willUpdate) {
      clearTimeout(timer);
      alert(content);
    } else {
      autoRefresh();
    }
  }, duration);
}
const env = process.env.UMI_ENV;

env == 'production' && autoRefresh();

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

成序猿@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值