最近项目进入测试阶段,因为是新项目首轮测试,要改要优化的东西太多,每次发完测试版后都要跟测试小姐姐说我发版了,你刷新一下可以验了,就很麻烦,像我这么社恐的人,每次开口都很艰难,于是,我弄了个自动检测更新的功能,只要测试那边在线(页面是打开状态),我发版后,页面上就会提示有更新,可以刷新页面进行更新。
- 开始之前咱先研究下开发环境下是怎么搞定热更新的,都知道项目在本地开发时都是有热更新的,只要修改保存后页面就会自动刷新或更新,这都借助了工程化构建工具,如果webpack-dev-server等。
其实都是基于socket来实现自动刷新的。当构建完成后,dev-server会启动一个http服务器,并在端口上监听。当我们打开本地地址时,页面中会嵌入一段socket脚本,该脚本会通过websocket连接到dev-server的socket服务器。
当本地文件发生变化时,会通知socket服务器,socket服务器收到通知后,会向客户端发送消息,客户端收到消息后,会刷新页面实现热更新。当然也不是所有的情况都会刷新,有些情况下是采用注入或者说是替换代码的形式来更新,如比小修改或者修改样式之类的。 - 为了这么一个小功能不可能去搞个socket来实现吧,太麻烦了不至于,于是直接上最简单粗暴的办法,那就是轮询,反正内网上公司自己的物理服务器,性能不用担心,是否优雅也不在考虑范围,直接看代码。
let lastSrcs:Array<string> = []
const scriptReg = /\<script.*src=["'](?<src>[^"']+)/gm;
async function extractNewScfipts():Promise<string[]> {
const html = await fetch('/?file=src/autoRefresh.ts&_timestamp='+Date.now()).then(res => res.text());
scriptReg.lastIndex = 0
let result = [];
let maech;
while ((maech = scriptReg.exec(html))) {
if(maech.groups) result.push(maech.groups.src)
}
return result
}
async function needUpdate():Promise<boolean>{
const newScripts = await extractNewScfipts()
if(!lastSrcs.length){
lastSrcs = newScripts
return false
}
let result = false
if(lastSrcs.length !== newScripts.length){
return true
}
for (let i = 0; i < lastSrcs.length; i++) {
if(lastSrcs[i] !== newScripts[i]){
result = true
break
}
}
lastSrcs = newScripts
return result
}
const DATEINIT = 1000 * 60
export function autoRefresh() {
setTimeout(async () => {
const willUpdate = await needUpdate();
if (willUpdate) {
const result = confirm('页面有更新,点击确定更新页面');
if (result) {
location.reload();
}
}
autoRefresh();
}, DATEINIT);
}
- 当然办法还有很多种,我就喜欢简单粗暴的这种。
- 有那说的不对的欢迎喷我,你们的攻击就是我前进的动力。嘿嘿!