swpp-backends 0.0.1-alpha
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +5 -0
- package/dist/SwppConfig.js +2 -0
- package/dist/UpdateJsonBuilder.js +281 -0
- package/dist/VersionAnalyzer.js +62 -0
- package/dist/fileAnalyzer.js +448 -0
- package/dist/index.js +35 -0
- package/dist/resources/sw-dom.js +51 -0
- package/dist/resources/sw-template.js +257 -0
- package/dist/serviceWorkerBuilder.js +152 -0
- package/dist/swppRules.js +117 -0
- package/dist/utils.js +188 -0
- package/package.json +37 -0
- package/types/SwppConfig.d.ts +125 -0
- package/types/UpdateJsonBuilder.d.ts +50 -0
- package/types/VersionAnalyzer.d.ts +29 -0
- package/types/fileAnalyzer.d.ts +147 -0
- package/types/index.d.ts +54 -0
- package/types/serviceWorkerBuilder.d.ts +7 -0
- package/types/swppRules.d.ts +101 -0
- package/types/utils.d.ts +41 -0
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.replaceRequest = exports.findCache = exports.eachAllLinkInJavaScript = exports.eachAllLinkInCss = exports.eachAllLinkInHtml = exports.eachAllLinkInUrl = exports.buildVersionJson = exports.readMergeVersionMap = exports.readNewVersionJson = exports.readOldVersionJson = exports.loadVersionJson = exports.isStable = exports.isExclude = void 0;
|
|
30
|
+
const fs_1 = __importDefault(require("fs"));
|
|
31
|
+
const path_1 = __importDefault(require("path"));
|
|
32
|
+
const node_fetch_1 = require("node-fetch");
|
|
33
|
+
const SwppRules_1 = require("./SwppRules");
|
|
34
|
+
const crypto = __importStar(require("crypto"));
|
|
35
|
+
const buffer_1 = require("buffer");
|
|
36
|
+
const fast_html_parser_1 = __importDefault(require("fast-html-parser"));
|
|
37
|
+
const css_1 = __importDefault(require("css"));
|
|
38
|
+
const Utils_1 = require("./Utils");
|
|
39
|
+
/**
|
|
40
|
+
* 遍历指定目录及其子目录中包含的所有文件(不遍历文件夹)
|
|
41
|
+
* @param root 根目录
|
|
42
|
+
* @param cb 回调函数(接收的参数是文件的相对路径)
|
|
43
|
+
*/
|
|
44
|
+
function eachAllFile(root, cb) {
|
|
45
|
+
const stats = fs_1.default.statSync(root);
|
|
46
|
+
if (stats.isFile())
|
|
47
|
+
cb(root);
|
|
48
|
+
else {
|
|
49
|
+
const files = fs_1.default.readdirSync(root);
|
|
50
|
+
files.forEach(it => eachAllFile(path_1.default.join(root, it), cb));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 判断指定 URL 是否排除
|
|
55
|
+
*
|
|
56
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
57
|
+
*
|
|
58
|
+
* @param webRoot 网站域名
|
|
59
|
+
* @param url 要判断的 URL
|
|
60
|
+
*/
|
|
61
|
+
function isExclude(webRoot, url) {
|
|
62
|
+
const exclude = (0, SwppRules_1.readRules)().config?.json?.exclude;
|
|
63
|
+
if (!exclude)
|
|
64
|
+
throw 'exclude 为空';
|
|
65
|
+
const list = isExternalLink(webRoot, url) ? exclude.other : exclude.localhost;
|
|
66
|
+
for (let reg of list) {
|
|
67
|
+
if (url.match(reg))
|
|
68
|
+
return true;
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
exports.isExclude = isExclude;
|
|
73
|
+
/**
|
|
74
|
+
* 判断指定 URL 是否是 stable 的
|
|
75
|
+
*
|
|
76
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
77
|
+
*/
|
|
78
|
+
function isStable(url) {
|
|
79
|
+
const stable = (0, SwppRules_1.readRules)().config?.external?.stable;
|
|
80
|
+
if (!stable)
|
|
81
|
+
throw 'stable 为空';
|
|
82
|
+
for (let reg of stable) {
|
|
83
|
+
if (url.match(reg))
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
exports.isStable = isStable;
|
|
89
|
+
/**
|
|
90
|
+
* 从指定 URL 加载 cache json
|
|
91
|
+
*
|
|
92
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
93
|
+
*/
|
|
94
|
+
async function loadVersionJson(url) {
|
|
95
|
+
const response = await (0, Utils_1.fetchFile)(url);
|
|
96
|
+
return _oldVersionJson = (await response.json());
|
|
97
|
+
}
|
|
98
|
+
exports.loadVersionJson = loadVersionJson;
|
|
99
|
+
let _oldVersionJson;
|
|
100
|
+
let _newVersionJson;
|
|
101
|
+
let _mergeVersionMap;
|
|
102
|
+
/**
|
|
103
|
+
* 读取最后一次加载的 version json
|
|
104
|
+
*
|
|
105
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
106
|
+
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
107
|
+
*/
|
|
108
|
+
function readOldVersionJson() {
|
|
109
|
+
if (!_oldVersionJson)
|
|
110
|
+
throw 'cache json 尚未初始化';
|
|
111
|
+
return _oldVersionJson;
|
|
112
|
+
}
|
|
113
|
+
exports.readOldVersionJson = readOldVersionJson;
|
|
114
|
+
/**
|
|
115
|
+
* 读取最后一次构建的 VersionJson
|
|
116
|
+
*
|
|
117
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
118
|
+
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
119
|
+
* + **执行该函数前必须调用过 [buildVersionJson]**
|
|
120
|
+
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
121
|
+
*/
|
|
122
|
+
function readNewVersionJson() {
|
|
123
|
+
if (!_newVersionJson)
|
|
124
|
+
throw 'cache json 尚未初始化';
|
|
125
|
+
return _newVersionJson;
|
|
126
|
+
}
|
|
127
|
+
exports.readNewVersionJson = readNewVersionJson;
|
|
128
|
+
/**
|
|
129
|
+
* 读取新旧版本文件合并后的版本地图
|
|
130
|
+
*
|
|
131
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
132
|
+
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
133
|
+
* + **执行该函数前必须调用过 [buildVersionJson]**
|
|
134
|
+
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
135
|
+
*/
|
|
136
|
+
function readMergeVersionMap() {
|
|
137
|
+
if (_mergeVersionMap)
|
|
138
|
+
return _mergeVersionMap;
|
|
139
|
+
const map = {};
|
|
140
|
+
Object.assign(map, readOldVersionJson().list);
|
|
141
|
+
Object.assign(map, readNewVersionJson().list);
|
|
142
|
+
return _mergeVersionMap = map;
|
|
143
|
+
}
|
|
144
|
+
exports.readMergeVersionMap = readMergeVersionMap;
|
|
145
|
+
/**
|
|
146
|
+
* 构建一个 cache json
|
|
147
|
+
*
|
|
148
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
149
|
+
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
150
|
+
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
151
|
+
*
|
|
152
|
+
* @param protocol 网站的网络协议
|
|
153
|
+
* @param webRoot 网站域名(包括二级域名)
|
|
154
|
+
* @param root 网页根目录(首页 index.html 所在目录)
|
|
155
|
+
*/
|
|
156
|
+
async function buildVersionJson(protocol, webRoot, root) {
|
|
157
|
+
const list = {};
|
|
158
|
+
eachAllFile(root, async (path) => {
|
|
159
|
+
const endIndex = path.length - (path.endsWith('/index.html') ? 10 : 0);
|
|
160
|
+
const url = new URL(protocol + path_1.default.join(webRoot, path.substring(root.length, endIndex)));
|
|
161
|
+
const pathname = url.pathname;
|
|
162
|
+
if (isExclude(webRoot, pathname))
|
|
163
|
+
return;
|
|
164
|
+
let content = null;
|
|
165
|
+
if (findCache(url)) {
|
|
166
|
+
content = fs_1.default.readFileSync(path, 'utf-8');
|
|
167
|
+
const key = decodeURIComponent(url.pathname);
|
|
168
|
+
list[key] = crypto.createHash('md5').update(content).digest('hex');
|
|
169
|
+
}
|
|
170
|
+
if (pathname.endsWith('/') || pathname.endsWith('.html')) {
|
|
171
|
+
if (!content)
|
|
172
|
+
content = fs_1.default.readFileSync(path, 'utf-8');
|
|
173
|
+
await eachAllLinkInHtml(webRoot, content, list);
|
|
174
|
+
}
|
|
175
|
+
else if (pathname.endsWith('.css')) {
|
|
176
|
+
if (!content)
|
|
177
|
+
content = fs_1.default.readFileSync(path, 'utf-8');
|
|
178
|
+
await eachAllLinkInCss(webRoot, content, list);
|
|
179
|
+
}
|
|
180
|
+
else if (pathname.endsWith('.js')) {
|
|
181
|
+
if (!content)
|
|
182
|
+
content = fs_1.default.readFileSync(path, 'utf-8');
|
|
183
|
+
await eachAllLinkInJavaScript(webRoot, content, list);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
return _newVersionJson = {
|
|
187
|
+
version: 3, list
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
exports.buildVersionJson = buildVersionJson;
|
|
191
|
+
/**
|
|
192
|
+
* 检索一个 URL 指向的文件中所有地外部链接
|
|
193
|
+
*
|
|
194
|
+
* 该函数会处理该 URL 指向的文件和文件中直接或间接包含的所有 URL
|
|
195
|
+
*
|
|
196
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
197
|
+
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
198
|
+
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
199
|
+
*
|
|
200
|
+
* @param webRoot 网站域名
|
|
201
|
+
* @param url 要检索的 URL
|
|
202
|
+
* @param result 存放结果的对象
|
|
203
|
+
* @param event 检索到一个 URL 时触发的事件
|
|
204
|
+
*/
|
|
205
|
+
async function eachAllLinkInUrl(webRoot, url, result, event) {
|
|
206
|
+
if (url.startsWith('//'))
|
|
207
|
+
url = 'http' + url;
|
|
208
|
+
if (url in result)
|
|
209
|
+
return event?.(url);
|
|
210
|
+
if (!url.startsWith('http') || isExclude(webRoot, url))
|
|
211
|
+
return;
|
|
212
|
+
if (!(isExternalLink(webRoot, url) && findCache(new URL(url))))
|
|
213
|
+
return;
|
|
214
|
+
event?.(url);
|
|
215
|
+
const stable = isStable(url);
|
|
216
|
+
if (stable) {
|
|
217
|
+
const old = readOldVersionJson().list;
|
|
218
|
+
if (url in old) {
|
|
219
|
+
const copyTree = (key) => {
|
|
220
|
+
const value = old[key];
|
|
221
|
+
if (!value)
|
|
222
|
+
return;
|
|
223
|
+
result[key] = value;
|
|
224
|
+
if (Array.isArray(value)) {
|
|
225
|
+
result[key] = value;
|
|
226
|
+
for (let url of value) {
|
|
227
|
+
copyTree(url);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
event?.(value);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
copyTree(url);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const response = await (0, Utils_1.fetchFile)(url);
|
|
239
|
+
if (![200, 301, 302, 307, 308].includes(response.status))
|
|
240
|
+
throw response;
|
|
241
|
+
const pathname = new URL(url).pathname;
|
|
242
|
+
let content;
|
|
243
|
+
const relay = [];
|
|
244
|
+
const nextEvent = (it) => {
|
|
245
|
+
relay.push(it);
|
|
246
|
+
event?.(it);
|
|
247
|
+
};
|
|
248
|
+
switch (true) {
|
|
249
|
+
case pathname.endsWith('.html'):
|
|
250
|
+
case pathname.endsWith('/'):
|
|
251
|
+
content = await response.text();
|
|
252
|
+
await eachAllLinkInHtml(webRoot, content, result, nextEvent);
|
|
253
|
+
break;
|
|
254
|
+
case pathname.endsWith('.css'):
|
|
255
|
+
content = await response.text();
|
|
256
|
+
await eachAllLinkInCss(webRoot, content, result, nextEvent);
|
|
257
|
+
break;
|
|
258
|
+
case pathname.endsWith('.js'):
|
|
259
|
+
content = await response.text();
|
|
260
|
+
await eachAllLinkInJavaScript(webRoot, content, result, nextEvent);
|
|
261
|
+
break;
|
|
262
|
+
default:
|
|
263
|
+
if (stable) {
|
|
264
|
+
result[url] = [];
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
const buffer = buffer_1.Buffer.from(await response.arrayBuffer());
|
|
268
|
+
result[url] = crypto.createHash('md5').update(buffer).digest('hex');
|
|
269
|
+
}
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
if (content) {
|
|
273
|
+
if (stable) {
|
|
274
|
+
result[url] = relay;
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
result[url] = crypto.createHash('md5').update(content).digest('hex');
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
exports.eachAllLinkInUrl = eachAllLinkInUrl;
|
|
282
|
+
/**
|
|
283
|
+
* 检索 HTML 文件中的所有外部链接
|
|
284
|
+
*
|
|
285
|
+
* 该函数仅处理 HTML 当中直接或间接包含的 URL,不处理文件本身
|
|
286
|
+
*
|
|
287
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
288
|
+
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
289
|
+
*
|
|
290
|
+
* @param webRoot 网站域名
|
|
291
|
+
* @param content HTML 文件内容
|
|
292
|
+
* @param result 存放结果的对象
|
|
293
|
+
* @param event 检索到 URL 时触发的事件
|
|
294
|
+
*/
|
|
295
|
+
async function eachAllLinkInHtml(webRoot, content, result, event) {
|
|
296
|
+
const each = async (node) => {
|
|
297
|
+
let url = undefined;
|
|
298
|
+
switch (node.tagName) {
|
|
299
|
+
case 'link':
|
|
300
|
+
url = node.attributes.href;
|
|
301
|
+
break;
|
|
302
|
+
case 'script':
|
|
303
|
+
case 'img':
|
|
304
|
+
case 'source':
|
|
305
|
+
case 'iframe':
|
|
306
|
+
case 'embed':
|
|
307
|
+
url = node.attributes.src;
|
|
308
|
+
break;
|
|
309
|
+
case 'object':
|
|
310
|
+
url = node.attributes.data;
|
|
311
|
+
break;
|
|
312
|
+
}
|
|
313
|
+
if (url) {
|
|
314
|
+
await eachAllLinkInUrl(webRoot, url, result, event);
|
|
315
|
+
}
|
|
316
|
+
else if (node.tagName === 'script') {
|
|
317
|
+
await eachAllLinkInJavaScript(webRoot, node.rawText, result, event);
|
|
318
|
+
}
|
|
319
|
+
else if (node.tagName === 'style') {
|
|
320
|
+
await eachAllLinkInCss(webRoot, node.rawText, result, event);
|
|
321
|
+
}
|
|
322
|
+
for (let childNode of node.childNodes) {
|
|
323
|
+
await each(childNode);
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
await each(fast_html_parser_1.default.parse(content, { style: true, script: true }));
|
|
327
|
+
}
|
|
328
|
+
exports.eachAllLinkInHtml = eachAllLinkInHtml;
|
|
329
|
+
/**
|
|
330
|
+
* 检索 CSS 文件中的所有外部链
|
|
331
|
+
*
|
|
332
|
+
* 该函数仅处理 CSS 当中直接或间接包含的 URL,不处理文件本身
|
|
333
|
+
*
|
|
334
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
335
|
+
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
336
|
+
*
|
|
337
|
+
* @param webRoot 网站域名
|
|
338
|
+
* @param content CSS 文件内容
|
|
339
|
+
* @param result 存放结果的对象
|
|
340
|
+
* @param event 当检索到一个 URL 后触发的事件
|
|
341
|
+
*/
|
|
342
|
+
async function eachAllLinkInCss(webRoot, content, result, event) {
|
|
343
|
+
const each = async (any) => {
|
|
344
|
+
if (!any)
|
|
345
|
+
return;
|
|
346
|
+
for (let rule of any) {
|
|
347
|
+
switch (rule.type) {
|
|
348
|
+
case 'rule':
|
|
349
|
+
await each(rule.declarations);
|
|
350
|
+
break;
|
|
351
|
+
case 'declaration':
|
|
352
|
+
const value = rule.value;
|
|
353
|
+
const list = value.match(/url\(['"]?([^'")]+)['"]?\)/g)
|
|
354
|
+
?.map(it => it.replace(/(^url\(['"])|(['"]\)$)/g, ''));
|
|
355
|
+
if (list) {
|
|
356
|
+
for (let url of list) {
|
|
357
|
+
await eachAllLinkInUrl(webRoot, url, result, event);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
break;
|
|
361
|
+
case 'import':
|
|
362
|
+
const url = rule.import.trim().replace(/^["']|["']$/g, '');
|
|
363
|
+
await eachAllLinkInUrl(webRoot, url, result, event);
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
await each(css_1.default.parse(content).stylesheet?.rules);
|
|
369
|
+
}
|
|
370
|
+
exports.eachAllLinkInCss = eachAllLinkInCss;
|
|
371
|
+
/**
|
|
372
|
+
* 遍历 JS 文件中地所有外部链接
|
|
373
|
+
*
|
|
374
|
+
* 该函数仅处理 JS 当中直接或间接包含的 URL,不处理文件本身
|
|
375
|
+
*
|
|
376
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
377
|
+
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
378
|
+
*
|
|
379
|
+
* @param webRoot 网站域名
|
|
380
|
+
* @param content JS 文件内容
|
|
381
|
+
* @param result 存放结果的对象
|
|
382
|
+
* @param event 当检索到一个 URL 后触发的事件
|
|
383
|
+
*/
|
|
384
|
+
async function eachAllLinkInJavaScript(webRoot, content, result, event) {
|
|
385
|
+
const ruleList = (0, SwppRules_1.readRules)().config?.external?.js;
|
|
386
|
+
if (!ruleList)
|
|
387
|
+
throw 'ruleList 为空';
|
|
388
|
+
for (let value of ruleList) {
|
|
389
|
+
if (typeof value === 'function') {
|
|
390
|
+
const urls = value(content);
|
|
391
|
+
for (let url of urls) {
|
|
392
|
+
await eachAllLinkInUrl(webRoot, url, result, event);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
const { head, tail } = value;
|
|
397
|
+
const reg = new RegExp(`${head}(['"\`])(.*?)(['"\`])${tail}`, 'mg');
|
|
398
|
+
const list = content.match(reg)
|
|
399
|
+
?.map(it => it.substring(head.length, it.length - tail.length).trim())
|
|
400
|
+
?.map(it => it.replace(/^['"`]|['"`]$/g, ''));
|
|
401
|
+
if (list) {
|
|
402
|
+
for (let url of list) {
|
|
403
|
+
await eachAllLinkInUrl(webRoot, url, result, event);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
exports.eachAllLinkInJavaScript = eachAllLinkInJavaScript;
|
|
410
|
+
/** 判断一个 URL 是否是外部链接 */
|
|
411
|
+
function isExternalLink(webRoot, url) {
|
|
412
|
+
return new RegExp(`^(https?:)?\\/\\/${webRoot}`).test(url);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
* 查询指定 URL 对应的缓存规则
|
|
416
|
+
*
|
|
417
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
418
|
+
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
419
|
+
*/
|
|
420
|
+
function findCache(url) {
|
|
421
|
+
const { cacheRules } = (0, SwppRules_1.readRules)();
|
|
422
|
+
const eject = (0, Utils_1.readEjectData)();
|
|
423
|
+
if (typeof url === 'string')
|
|
424
|
+
url = new URL(url);
|
|
425
|
+
url = new URL(replaceRequest(url.href));
|
|
426
|
+
for (let key in cacheRules) {
|
|
427
|
+
const value = cacheRules[key];
|
|
428
|
+
if (value.match(url, eject.nodeEject))
|
|
429
|
+
return value;
|
|
430
|
+
}
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
exports.findCache = findCache;
|
|
434
|
+
/**
|
|
435
|
+
* 替换请求
|
|
436
|
+
*
|
|
437
|
+
* + **执行该函数前必须调用过 [loadRules]**
|
|
438
|
+
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
439
|
+
*/
|
|
440
|
+
function replaceRequest(url) {
|
|
441
|
+
const rules = (0, SwppRules_1.readRules)();
|
|
442
|
+
if (!('modifyRequest' in rules))
|
|
443
|
+
return url;
|
|
444
|
+
const { modifyRequest } = rules;
|
|
445
|
+
const request = new node_fetch_1.Request(url);
|
|
446
|
+
return modifyRequest?.(request, (0, Utils_1.readEjectData)().nodeEject)?.url ?? url;
|
|
447
|
+
}
|
|
448
|
+
exports.replaceRequest = replaceRequest;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const Utils_1 = require("./Utils");
|
|
4
|
+
const FileAnalyzer_1 = require("./FileAnalyzer");
|
|
5
|
+
const ServiceWorkerBuilder_1 = require("./ServiceWorkerBuilder");
|
|
6
|
+
const SwppRules_1 = require("./SwppRules");
|
|
7
|
+
const UpdateJsonBuilder_1 = require("./UpdateJsonBuilder");
|
|
8
|
+
const VersionAnalyzer_1 = require("./VersionAnalyzer");
|
|
9
|
+
// noinspection JSUnusedGlobalSymbols
|
|
10
|
+
exports.default = {
|
|
11
|
+
cache: {
|
|
12
|
+
readEjectData: Utils_1.readEjectData, readUpdateJson: UpdateJsonBuilder_1.readUpdateJson,
|
|
13
|
+
readRules: SwppRules_1.readRules, readMergeVersionMap: FileAnalyzer_1.readMergeVersionMap,
|
|
14
|
+
readOldVersionJson: FileAnalyzer_1.readOldVersionJson, readNewVersionJson: FileAnalyzer_1.readNewVersionJson
|
|
15
|
+
},
|
|
16
|
+
builder: {
|
|
17
|
+
buildServiceWorker: ServiceWorkerBuilder_1.buildServiceWorker,
|
|
18
|
+
buildVersionJson: FileAnalyzer_1.buildVersionJson,
|
|
19
|
+
buildNewInfo: UpdateJsonBuilder_1.buildNewInfo,
|
|
20
|
+
calcEjectValues: Utils_1.calcEjectValues,
|
|
21
|
+
analyzer: VersionAnalyzer_1.analyzer
|
|
22
|
+
},
|
|
23
|
+
loader: {
|
|
24
|
+
loadRules: SwppRules_1.loadRules, loadUpdateJson: UpdateJsonBuilder_1.loadUpdateJson, loadVersionJson: FileAnalyzer_1.loadVersionJson
|
|
25
|
+
},
|
|
26
|
+
event: {
|
|
27
|
+
addRulesMapEvent: SwppRules_1.addRulesMapEvent, refreshUrl: VersionAnalyzer_1.refreshUrl, submitChange: UpdateJsonBuilder_1.submitChange
|
|
28
|
+
},
|
|
29
|
+
utils: {
|
|
30
|
+
getSource: Utils_1.getSource, getShorthand: UpdateJsonBuilder_1.getShorthand, findCache: FileAnalyzer_1.findCache,
|
|
31
|
+
fetchFile: Utils_1.fetchFile, replaceDevRequest: Utils_1.replaceDevRequest, replaceRequest: FileAnalyzer_1.replaceRequest,
|
|
32
|
+
isStable: FileAnalyzer_1.isStable, isExclude: FileAnalyzer_1.isExclude,
|
|
33
|
+
eachAllLinkInUrl: FileAnalyzer_1.eachAllLinkInUrl, eachAllLinkInHtml: FileAnalyzer_1.eachAllLinkInHtml, eachAllLinkInCss: FileAnalyzer_1.eachAllLinkInCss, eachAllLinkInJavaScript: FileAnalyzer_1.eachAllLinkInJavaScript
|
|
34
|
+
}
|
|
35
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
document.addEventListener('DOMContentLoaded', () => {
|
|
2
|
+
/** 检查 SW 是否可用 */
|
|
3
|
+
const checkServiceWorker = () => 'serviceWorker' in navigator && navigator.serviceWorker.controller
|
|
4
|
+
/** 发送信息到 sw */
|
|
5
|
+
const postMessage2SW = type => navigator.serviceWorker.controller.postMessage(type)
|
|
6
|
+
const pjaxUpdate = url => new Promise(resolve => {
|
|
7
|
+
const type = url.endsWith('js') ? 'script' : 'link'
|
|
8
|
+
const name = type.length === 4 ? 'href' : 'src'
|
|
9
|
+
for (let item of document.querySelectorAll(type)) {
|
|
10
|
+
const itUrl = item[name]
|
|
11
|
+
if (url.length > itUrl ? url.endsWith(itUrl) : itUrl.endsWith(url)) {
|
|
12
|
+
const newEle = document.createElement(type)
|
|
13
|
+
const content = item.text || item.textContent || item.innerHTML || ''
|
|
14
|
+
Array.from(item.attributes).forEach(attr => newEle.setAttribute(attr.name, attr.value))
|
|
15
|
+
newEle.appendChild(document.createTextNode(content))
|
|
16
|
+
item.parentNode.replaceChildren(newEle, item)
|
|
17
|
+
return resolve(true)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
resolve(false)
|
|
21
|
+
})
|
|
22
|
+
if (!checkServiceWorker()) return
|
|
23
|
+
if (sessionStorage.getItem('updated')) {
|
|
24
|
+
sessionStorage.removeItem('updated')
|
|
25
|
+
// ${onSuccess}
|
|
26
|
+
} else postMessage2SW('update')
|
|
27
|
+
navigator.serviceWorker.addEventListener('message', event => {
|
|
28
|
+
const data = event.data
|
|
29
|
+
switch (data.type) {
|
|
30
|
+
case 'update':
|
|
31
|
+
const list = data.update
|
|
32
|
+
if (!list) break
|
|
33
|
+
sessionStorage.setItem('updated', '1')
|
|
34
|
+
// noinspection JSUnresolvedVariable,JSUnresolvedFunction
|
|
35
|
+
if (window.Pjax?.isSupported()) {
|
|
36
|
+
Promise.all(list.map(url => {
|
|
37
|
+
if (url.endsWith('.js'))
|
|
38
|
+
return pjaxUpdate(url)
|
|
39
|
+
if (url.endsWith('.css'))
|
|
40
|
+
return pjaxUpdate(url)
|
|
41
|
+
return Promise.resolve()
|
|
42
|
+
})).then(() => location.reload())
|
|
43
|
+
} else location.reload()
|
|
44
|
+
break
|
|
45
|
+
case 'escape':
|
|
46
|
+
sessionStorage.setItem('updated', '1')
|
|
47
|
+
location.reload()
|
|
48
|
+
break
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
})
|