versionUpdater.js
3.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/*
* @Date: 2024-02-06 11:38:13
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-02-06 13:04:25
* @FilePath: /xysBooking/src/utils/versionUpdater.js
* @Description: 轮询检测静态资源变更(用于提示用户刷新页面)
*/
/* eslint-disable */
/**
* 版本更新检查器
* - 思路:定时拉取 index.html,对比其中 <script> 标签内容是否发生变化
* - 适用:Vite 构建的产物文件名带 hash,更新后 script src 会变化
* @class
*/
export class Updater {
/**
* @param {{ time?: number }} options 配置项
*/
constructor(options = {}) {
this.oldScript = [];
this.newScript = [];
this.dispatch = {};
this.init(); //初始化
this.timing(options.time); //轮询
}
/**
* 初始化:读取当前 html 并记录 script 标签快照
* @returns {Promise<void>}
*/
async init() {
const html = await this.getHtml();
this.oldScript = this.parserScript(html);
}
/**
* 拉取 index.html 文本内容
* @returns {Promise<string>} html 文本
*/
async getHtml() {
// TAG: html的位置需要动态修改
const html = await fetch(import.meta.env.VITE_BASE).then((res) => res.text()); //读取index html
return html;
}
/**
* 解析 html 中的 script 标签字符串数组
* @param {string} html html 文本
* @returns {string[]|null} script 标签数组(match 可能返回 null)
*/
parserScript(html) {
const reg = new RegExp(/<script(?:\s+[^>]*)?>(.*?)<\/script\s*>/gi); //script正则
return html.match(reg); //匹配script标签
}
/**
* 订阅事件
* @param {'no-update'|'update'|string} key 事件名
* @param {Function} fn 回调函数
* @returns {Updater} 当前实例,便于链式调用
*/
on(key, fn) {
(this.dispatch[key] || (this.dispatch[key] = [])).push(fn);
return this;
}
/**
* 对比两次 script 标签快照
* @param {string[]|null} oldArr 旧快照
* @param {string[]|null} newArr 新快照
* @returns {void}
*/
compare(oldArr, newArr) {
// 兼容 match 返回 null 的场景,避免 compare 触发运行时异常
const safeOldArr = Array.isArray(oldArr) ? oldArr : [];
const safeNewArr = Array.isArray(newArr) ? newArr : [];
const base = safeOldArr.length;
// 去重
const arr = Array.from(new Set(safeOldArr.concat(safeNewArr)));
//如果新旧length 一样无更新
if (arr.length === base) {
const fns = Array.isArray(this.dispatch['no-update']) ? this.dispatch['no-update'] : [];
fns.forEach((fn) => fn());
} else {
//否则通知更新
const fns = Array.isArray(this.dispatch['update']) ? this.dispatch['update'] : [];
fns.forEach((fn) => fn());
}
}
/**
* 开始轮询
* @param {number} time 轮询间隔(毫秒)
* @returns {void}
*/
timing(time = 10000) {
//轮询
setInterval(async () => {
const newHtml = await this.getHtml();
this.newScript = this.parserScript(newHtml);
this.compare(this.oldScript, this.newScript);
}, time);
}
}