swpp-backends 1.0.12 → 1.0.13
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/package.json +1 -1
- package/dist/js/Import.js +0 -3
- package/dist/ts/FileAnalyzer.js +0 -499
- package/dist/ts/ServiceWorkerBuilder.js +0 -152
- package/dist/ts/SwppConfig.js +0 -2
- package/dist/ts/SwppRules.js +0 -122
- package/dist/ts/UpdateJsonBuilder.js +0 -310
- package/dist/ts/Utils.js +0 -201
- package/dist/ts/VersionAnalyzer.js +0 -64
- package/dist/ts/index.js +0 -35
- package/types/ts/FileAnalyzer.d.ts +0 -154
- package/types/ts/ServiceWorkerBuilder.d.ts +0 -7
- package/types/ts/SwppConfig.d.ts +0 -125
- package/types/ts/SwppRules.d.ts +0 -102
- package/types/ts/UpdateJsonBuilder.d.ts +0 -50
- package/types/ts/Utils.d.ts +0 -42
- package/types/ts/VersionAnalyzer.d.ts +0 -29
- package/types/ts/index.d.ts +0 -55
package/package.json
CHANGED
package/dist/js/Import.js
DELETED
package/dist/ts/FileAnalyzer.js
DELETED
|
@@ -1,499 +0,0 @@
|
|
|
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.submitCacheInfo = exports.loadVersionJson = exports.isStable = exports.isExclude = void 0;
|
|
30
|
-
const fs_1 = __importDefault(require("fs"));
|
|
31
|
-
const path_1 = __importDefault(require("path"));
|
|
32
|
-
const SwppRules_1 = require("./SwppRules");
|
|
33
|
-
const crypto = __importStar(require("crypto"));
|
|
34
|
-
const fast_html_parser_1 = __importDefault(require("fast-html-parser"));
|
|
35
|
-
const css_1 = __importDefault(require("css"));
|
|
36
|
-
const Utils_1 = require("./Utils");
|
|
37
|
-
/**
|
|
38
|
-
* 遍历指定目录及其子目录中包含的所有文件(不遍历文件夹)
|
|
39
|
-
* @param root 根目录
|
|
40
|
-
* @param cb 回调函数(接收的参数是文件的相对路径)
|
|
41
|
-
*/
|
|
42
|
-
async function eachAllFile(root, cb) {
|
|
43
|
-
const stats = fs_1.default.statSync(root);
|
|
44
|
-
if (stats.isFile())
|
|
45
|
-
await cb(root);
|
|
46
|
-
else {
|
|
47
|
-
const files = fs_1.default.readdirSync(root);
|
|
48
|
-
await Promise.all(files.map(it => eachAllFile(path_1.default.join(root, it), cb)));
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* 判断指定 URL 是否排除
|
|
53
|
-
*
|
|
54
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
55
|
-
*
|
|
56
|
-
* @param domain 网站域名
|
|
57
|
-
* @param url 要判断的 URL
|
|
58
|
-
*/
|
|
59
|
-
function isExclude(domain, url) {
|
|
60
|
-
const exclude = (0, SwppRules_1.readRules)().config?.json?.exclude;
|
|
61
|
-
if (!exclude)
|
|
62
|
-
return false;
|
|
63
|
-
const list = isExternalLink(domain, url) ? exclude.other : exclude.localhost;
|
|
64
|
-
for (let reg of list) {
|
|
65
|
-
if (url.match(reg))
|
|
66
|
-
return true;
|
|
67
|
-
}
|
|
68
|
-
return false;
|
|
69
|
-
}
|
|
70
|
-
exports.isExclude = isExclude;
|
|
71
|
-
/**
|
|
72
|
-
* 判断指定 URL 是否是 stable 的
|
|
73
|
-
*
|
|
74
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
75
|
-
*/
|
|
76
|
-
function isStable(url) {
|
|
77
|
-
const stable = (0, SwppRules_1.readRules)().config?.external?.stable;
|
|
78
|
-
if (!stable)
|
|
79
|
-
return false;
|
|
80
|
-
for (let reg of stable) {
|
|
81
|
-
if (url.match(reg))
|
|
82
|
-
return true;
|
|
83
|
-
}
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
exports.isStable = isStable;
|
|
87
|
-
/**
|
|
88
|
-
* 从指定 URL 加载 version json
|
|
89
|
-
*
|
|
90
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
91
|
-
*/
|
|
92
|
-
async function loadVersionJson(url) {
|
|
93
|
-
const response = await (0, Utils_1.fetchFile)(url).catch(err => err);
|
|
94
|
-
if (response?.statusCode === 404) {
|
|
95
|
-
(0, Utils_1.warn)('LoadVersionJson', `拉取 ${url} 时出现 404 错误,如果您是第一次构建请忽略这个警告。`);
|
|
96
|
-
return _oldVersionJson = null;
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
return _oldVersionJson = (JSON.parse(response.body));
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
exports.loadVersionJson = loadVersionJson;
|
|
103
|
-
let _oldVersionJson = undefined;
|
|
104
|
-
let _newVersionJson;
|
|
105
|
-
let _mergeVersionMap;
|
|
106
|
-
const event = new Map();
|
|
107
|
-
/** 提交要存储到 version json 的值 */
|
|
108
|
-
function submitCacheInfo(key, value) {
|
|
109
|
-
event.set(key, value);
|
|
110
|
-
}
|
|
111
|
-
exports.submitCacheInfo = submitCacheInfo;
|
|
112
|
-
/**
|
|
113
|
-
* 读取最后一次加载的 version json
|
|
114
|
-
*
|
|
115
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
116
|
-
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
117
|
-
*/
|
|
118
|
-
function readOldVersionJson() {
|
|
119
|
-
if (_oldVersionJson === undefined) {
|
|
120
|
-
(0, Utils_1.error)('OldVersionReader', 'version json 尚未初始化');
|
|
121
|
-
throw 'version json 尚未初始化';
|
|
122
|
-
}
|
|
123
|
-
return _oldVersionJson;
|
|
124
|
-
}
|
|
125
|
-
exports.readOldVersionJson = readOldVersionJson;
|
|
126
|
-
/**
|
|
127
|
-
* 读取最后一次构建的 VersionJson
|
|
128
|
-
*
|
|
129
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
130
|
-
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
131
|
-
* + **执行该函数前必须调用过 [buildVersionJson]**
|
|
132
|
-
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
133
|
-
*/
|
|
134
|
-
function readNewVersionJson() {
|
|
135
|
-
if (!_newVersionJson) {
|
|
136
|
-
(0, Utils_1.error)('NewVersionReader', 'version json 尚未初始化');
|
|
137
|
-
throw 'version json 尚未初始化';
|
|
138
|
-
}
|
|
139
|
-
return _newVersionJson;
|
|
140
|
-
}
|
|
141
|
-
exports.readNewVersionJson = readNewVersionJson;
|
|
142
|
-
/**
|
|
143
|
-
* 读取新旧版本文件合并后的版本地图
|
|
144
|
-
*
|
|
145
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
146
|
-
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
147
|
-
* + **执行该函数前必须调用过 [buildVersionJson]**
|
|
148
|
-
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
149
|
-
*/
|
|
150
|
-
function readMergeVersionMap() {
|
|
151
|
-
if (_mergeVersionMap)
|
|
152
|
-
return _mergeVersionMap;
|
|
153
|
-
const map = {};
|
|
154
|
-
Object.assign(map, readOldVersionJson()?.list ?? {});
|
|
155
|
-
Object.assign(map, readNewVersionJson().list);
|
|
156
|
-
return _mergeVersionMap = map;
|
|
157
|
-
}
|
|
158
|
-
exports.readMergeVersionMap = readMergeVersionMap;
|
|
159
|
-
/**
|
|
160
|
-
* 构建一个 version json
|
|
161
|
-
*
|
|
162
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
163
|
-
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
164
|
-
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
165
|
-
*
|
|
166
|
-
* @param protocol 网站的网络协议
|
|
167
|
-
* @param domain 网站域名(包括二级域名)
|
|
168
|
-
* @param root 网页根目录(首页 index.html 所在目录)
|
|
169
|
-
*/
|
|
170
|
-
async function buildVersionJson(protocol, domain, root) {
|
|
171
|
-
const list = {};
|
|
172
|
-
await eachAllFile(root, async (path) => {
|
|
173
|
-
const endIndex = path.length - (/[\/\\]index\.html$/.test(path) ? 10 : 0);
|
|
174
|
-
const url = new URL(protocol + path_1.default.join(domain, path.substring(root.length, endIndex)));
|
|
175
|
-
const pathname = url.pathname;
|
|
176
|
-
if (isExclude(domain, pathname))
|
|
177
|
-
return;
|
|
178
|
-
let content = null;
|
|
179
|
-
if (findCache(url)) {
|
|
180
|
-
content = fs_1.default.readFileSync(path, 'utf-8');
|
|
181
|
-
const key = decodeURIComponent(url.pathname);
|
|
182
|
-
list[key] = crypto.createHash('md5').update(content).digest('hex');
|
|
183
|
-
}
|
|
184
|
-
if (pathname.endsWith('/') || pathname.endsWith('.html')) {
|
|
185
|
-
if (!content)
|
|
186
|
-
content = fs_1.default.readFileSync(path, 'utf-8');
|
|
187
|
-
await eachAllLinkInHtml(domain, protocol + domain, content, list);
|
|
188
|
-
}
|
|
189
|
-
else if (pathname.endsWith('.css')) {
|
|
190
|
-
if (!content)
|
|
191
|
-
content = fs_1.default.readFileSync(path, 'utf-8');
|
|
192
|
-
await eachAllLinkInCss(domain, protocol + domain, content, list);
|
|
193
|
-
}
|
|
194
|
-
else if (pathname.endsWith('.js')) {
|
|
195
|
-
if (!content)
|
|
196
|
-
content = fs_1.default.readFileSync(path, 'utf-8');
|
|
197
|
-
await eachAllLinkInJavaScript(domain, content, list);
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
const external = {};
|
|
201
|
-
event.forEach((value, key) => {
|
|
202
|
-
external[key] = value;
|
|
203
|
-
});
|
|
204
|
-
return _newVersionJson = {
|
|
205
|
-
version: 3, list, external
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
exports.buildVersionJson = buildVersionJson;
|
|
209
|
-
/**
|
|
210
|
-
* 检索一个 URL 指向的文件中所有地外部链接
|
|
211
|
-
*
|
|
212
|
-
* 该函数会处理该 URL 指向的文件和文件中直接或间接包含的所有 URL
|
|
213
|
-
*
|
|
214
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
215
|
-
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
216
|
-
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
217
|
-
*
|
|
218
|
-
* @param domain 网站域名
|
|
219
|
-
* @param url 要检索的 URL
|
|
220
|
-
* @param result 存放结果的对象
|
|
221
|
-
* @param event 检索到一个 URL 时触发的事件
|
|
222
|
-
*/
|
|
223
|
-
async function eachAllLinkInUrl(domain, url, result, event) {
|
|
224
|
-
if (url.startsWith('//'))
|
|
225
|
-
url = 'http:' + url;
|
|
226
|
-
if (url in result)
|
|
227
|
-
return event?.(url);
|
|
228
|
-
if (!url.startsWith('http') || isExclude(domain, url))
|
|
229
|
-
return;
|
|
230
|
-
if (!(isExternalLink(domain, url) && findCache(new URL(url))))
|
|
231
|
-
return;
|
|
232
|
-
const stable = isStable(url);
|
|
233
|
-
if (stable) {
|
|
234
|
-
const old = readOldVersionJson()?.list;
|
|
235
|
-
if (Array.isArray(old?.[url])) {
|
|
236
|
-
const copyTree = (key) => {
|
|
237
|
-
const value = old[key];
|
|
238
|
-
if (!value)
|
|
239
|
-
return;
|
|
240
|
-
result[key] = value;
|
|
241
|
-
if (Array.isArray(value)) {
|
|
242
|
-
result[key] = value;
|
|
243
|
-
for (let url of value) {
|
|
244
|
-
copyTree(url);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
copyTree(url);
|
|
249
|
-
event?.(url);
|
|
250
|
-
return;
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
const response = await (0, Utils_1.fetchFile)(url).catch(err => err);
|
|
254
|
-
if (![200, 301, 302, 307, 308].includes(response?.statusCode ?? 0)) {
|
|
255
|
-
(0, Utils_1.error)('LinkItorInUrl', `拉取文件 [${url}] 时出现错误:${response?.statusCode}`);
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
event?.(url);
|
|
259
|
-
const pathname = new URL(url).pathname;
|
|
260
|
-
let content;
|
|
261
|
-
const nextEvent = (it) => {
|
|
262
|
-
if (stable)
|
|
263
|
-
result[url].push(it);
|
|
264
|
-
};
|
|
265
|
-
const update = () => {
|
|
266
|
-
if (stable)
|
|
267
|
-
result[url] = [];
|
|
268
|
-
else
|
|
269
|
-
result[url] = crypto.createHash('md5').update(content).digest('hex');
|
|
270
|
-
};
|
|
271
|
-
switch (true) {
|
|
272
|
-
case pathname.endsWith('.html'):
|
|
273
|
-
case pathname.endsWith('/'):
|
|
274
|
-
content = response.body;
|
|
275
|
-
update();
|
|
276
|
-
return eachAllLinkInHtml(domain, url.substring(0, url.lastIndexOf('/') + 1), content, result, nextEvent);
|
|
277
|
-
case pathname.endsWith('.css'):
|
|
278
|
-
content = response.body;
|
|
279
|
-
update();
|
|
280
|
-
return eachAllLinkInCss(domain, url.substring(0, url.lastIndexOf('/') + 1), content, result, nextEvent);
|
|
281
|
-
case pathname.endsWith('.js'):
|
|
282
|
-
content = response.body;
|
|
283
|
-
update();
|
|
284
|
-
return eachAllLinkInJavaScript(domain, content, result, nextEvent);
|
|
285
|
-
default:
|
|
286
|
-
if (stable) {
|
|
287
|
-
result[url] = [];
|
|
288
|
-
}
|
|
289
|
-
else {
|
|
290
|
-
result[url] = crypto.createHash('md5').update(response.rawBody).digest('hex');
|
|
291
|
-
}
|
|
292
|
-
break;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
exports.eachAllLinkInUrl = eachAllLinkInUrl;
|
|
296
|
-
/**
|
|
297
|
-
* 检索 HTML 文件中的所有外部链接
|
|
298
|
-
*
|
|
299
|
-
* 该函数仅处理 HTML 当中直接或间接包含的 URL,不处理文件本身
|
|
300
|
-
*
|
|
301
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
302
|
-
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
303
|
-
*
|
|
304
|
-
* @param domain 网站域名
|
|
305
|
-
* @param root 当前资源的根
|
|
306
|
-
* @param content HTML 文件内容
|
|
307
|
-
* @param result 存放结果的对象
|
|
308
|
-
* @param event 检索到 URL 时触发的事件
|
|
309
|
-
*/
|
|
310
|
-
async function eachAllLinkInHtml(domain, root, content, result, event) {
|
|
311
|
-
const taskList = [];
|
|
312
|
-
const each = (node) => {
|
|
313
|
-
let url = undefined;
|
|
314
|
-
switch (node.tagName) {
|
|
315
|
-
case 'link':
|
|
316
|
-
// noinspection SpellCheckingInspection
|
|
317
|
-
if (node.attributes.rel !== 'preconnect')
|
|
318
|
-
url = node.attributes.href;
|
|
319
|
-
break;
|
|
320
|
-
case 'script':
|
|
321
|
-
case 'img':
|
|
322
|
-
case 'source':
|
|
323
|
-
case 'iframe':
|
|
324
|
-
case 'embed':
|
|
325
|
-
url = node.attributes.src;
|
|
326
|
-
break;
|
|
327
|
-
case 'object':
|
|
328
|
-
url = node.attributes.data;
|
|
329
|
-
break;
|
|
330
|
-
}
|
|
331
|
-
if (url) {
|
|
332
|
-
taskList.push(eachAllLinkInUrl(domain, url, result, event));
|
|
333
|
-
}
|
|
334
|
-
else if (node.tagName === 'script') {
|
|
335
|
-
taskList.push(eachAllLinkInJavaScript(domain, node.rawText, result, event));
|
|
336
|
-
}
|
|
337
|
-
else if (node.tagName === 'style') {
|
|
338
|
-
taskList.push(eachAllLinkInCss(domain, root, node.rawText, result, event));
|
|
339
|
-
}
|
|
340
|
-
if (node.childNodes) {
|
|
341
|
-
for (let childNode of node.childNodes) {
|
|
342
|
-
each(childNode);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
};
|
|
346
|
-
let html;
|
|
347
|
-
try {
|
|
348
|
-
html = fast_html_parser_1.default.parse(content, { style: true, script: true });
|
|
349
|
-
}
|
|
350
|
-
catch (e) {
|
|
351
|
-
(0, Utils_1.error)('HtmlParser', `HTML [root=${root}] 中存在错误语法`);
|
|
352
|
-
}
|
|
353
|
-
if (html)
|
|
354
|
-
each(html);
|
|
355
|
-
return Promise.all(taskList);
|
|
356
|
-
}
|
|
357
|
-
exports.eachAllLinkInHtml = eachAllLinkInHtml;
|
|
358
|
-
/**
|
|
359
|
-
* 检索 CSS 文件中的所有外部链
|
|
360
|
-
*
|
|
361
|
-
* 该函数仅处理 CSS 当中直接或间接包含的 URL,不处理文件本身
|
|
362
|
-
*
|
|
363
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
364
|
-
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
365
|
-
*
|
|
366
|
-
* @param domain 网站域名
|
|
367
|
-
* @param root 当前资源的 URL 的根
|
|
368
|
-
* @param content CSS 文件内容
|
|
369
|
-
* @param result 存放结果的对象
|
|
370
|
-
* @param event 当检索到一个 URL 后触发的事件
|
|
371
|
-
*/
|
|
372
|
-
async function eachAllLinkInCss(domain, root, content, result, event) {
|
|
373
|
-
const taskList = [];
|
|
374
|
-
const each = (any) => {
|
|
375
|
-
if (!any)
|
|
376
|
-
return;
|
|
377
|
-
for (let rule of any) {
|
|
378
|
-
if (rule.declarations)
|
|
379
|
-
each(rule.declarations);
|
|
380
|
-
switch (rule.type) {
|
|
381
|
-
case 'declaration':
|
|
382
|
-
const value = rule.value;
|
|
383
|
-
const list = value.match(/url\(['"]?([^'")]+)['"]?\)/g)
|
|
384
|
-
?.map(it => it.replace(/(^url\(['"]?)|(['"]?\)$)/g, ''));
|
|
385
|
-
if (list) {
|
|
386
|
-
for (let url of list) {
|
|
387
|
-
if (!/^(https?:)|(\/\/)/.test(url)) {
|
|
388
|
-
if (url[0] === '/')
|
|
389
|
-
url = root + url.substring(1);
|
|
390
|
-
else
|
|
391
|
-
url = root + url;
|
|
392
|
-
}
|
|
393
|
-
taskList.push(eachAllLinkInUrl(domain, url, result, event));
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
break;
|
|
397
|
-
case 'import':
|
|
398
|
-
const url = rule.import.trim().replace(/^["']|["']$/g, '');
|
|
399
|
-
taskList.push(eachAllLinkInUrl(domain, url, result, event));
|
|
400
|
-
break;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
};
|
|
404
|
-
let css;
|
|
405
|
-
try {
|
|
406
|
-
css = css_1.default.parse(content).stylesheet?.rules;
|
|
407
|
-
}
|
|
408
|
-
catch (e) {
|
|
409
|
-
(0, Utils_1.error)('CssParser', `CSS [root=${root}] 中存在错误语法`);
|
|
410
|
-
}
|
|
411
|
-
if (css)
|
|
412
|
-
each(css);
|
|
413
|
-
return Promise.all(taskList);
|
|
414
|
-
}
|
|
415
|
-
exports.eachAllLinkInCss = eachAllLinkInCss;
|
|
416
|
-
/**
|
|
417
|
-
* 遍历 JS 文件中地所有外部链接
|
|
418
|
-
*
|
|
419
|
-
* 该函数仅处理 JS 当中直接或间接包含的 URL,不处理文件本身
|
|
420
|
-
*
|
|
421
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
422
|
-
* + **调用该函数前必须调用过 [loadCacheJson]**
|
|
423
|
-
*
|
|
424
|
-
* @param domain 网站域名
|
|
425
|
-
* @param content JS 文件内容
|
|
426
|
-
* @param result 存放结果的对象
|
|
427
|
-
* @param event 当检索到一个 URL 后触发的事件
|
|
428
|
-
*/
|
|
429
|
-
function eachAllLinkInJavaScript(domain, content, result, event) {
|
|
430
|
-
const taskList = [];
|
|
431
|
-
const ruleList = (0, SwppRules_1.readRules)().config?.external?.js;
|
|
432
|
-
if (!ruleList) {
|
|
433
|
-
(0, Utils_1.error)('LinkItorInJS', '不应发生的异常');
|
|
434
|
-
throw 'ruleList 为空';
|
|
435
|
-
}
|
|
436
|
-
for (let value of ruleList) {
|
|
437
|
-
if (typeof value === 'function') {
|
|
438
|
-
const urls = value(content);
|
|
439
|
-
for (let url of urls) {
|
|
440
|
-
taskList.push(eachAllLinkInUrl(domain, url, result, event));
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
else {
|
|
444
|
-
const { head, tail } = value;
|
|
445
|
-
const reg = new RegExp(`${head}(['"\`])(.*?)(['"\`])${tail}`, 'mg');
|
|
446
|
-
const list = content.match(reg)
|
|
447
|
-
?.map(it => it.substring(head.length, it.length - tail.length).trim())
|
|
448
|
-
?.map(it => it.replace(/^['"`]|['"`]$/g, ''));
|
|
449
|
-
if (list) {
|
|
450
|
-
for (let url of list) {
|
|
451
|
-
taskList.push(eachAllLinkInUrl(domain, url, result, event));
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
return Promise.all(taskList);
|
|
457
|
-
}
|
|
458
|
-
exports.eachAllLinkInJavaScript = eachAllLinkInJavaScript;
|
|
459
|
-
/** 判断一个 URL 是否是外部链接 */
|
|
460
|
-
function isExternalLink(domain, url) {
|
|
461
|
-
if (url[0] === '/' && url[1] !== '/')
|
|
462
|
-
return false;
|
|
463
|
-
return !new RegExp(`^(https?:)?\\/\\/${domain}`).test(url);
|
|
464
|
-
}
|
|
465
|
-
/**
|
|
466
|
-
* 查询指定 URL 对应的缓存规则
|
|
467
|
-
*
|
|
468
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
469
|
-
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
470
|
-
*/
|
|
471
|
-
function findCache(url) {
|
|
472
|
-
const { cacheRules } = (0, SwppRules_1.readRules)();
|
|
473
|
-
const eject = (0, Utils_1.readEjectData)();
|
|
474
|
-
if (typeof url === 'string')
|
|
475
|
-
url = new URL(url);
|
|
476
|
-
url = new URL(replaceRequest(url.href));
|
|
477
|
-
for (let key in cacheRules) {
|
|
478
|
-
const value = cacheRules[key];
|
|
479
|
-
if (value.match(url, eject?.nodeEject))
|
|
480
|
-
return value;
|
|
481
|
-
}
|
|
482
|
-
return null;
|
|
483
|
-
}
|
|
484
|
-
exports.findCache = findCache;
|
|
485
|
-
/**
|
|
486
|
-
* 替换请求
|
|
487
|
-
*
|
|
488
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
489
|
-
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
490
|
-
*/
|
|
491
|
-
function replaceRequest(url) {
|
|
492
|
-
const rules = (0, SwppRules_1.readRules)();
|
|
493
|
-
if (!('modifyRequest' in rules))
|
|
494
|
-
return url;
|
|
495
|
-
const { modifyRequest } = rules;
|
|
496
|
-
const request = new Request(url);
|
|
497
|
-
return modifyRequest?.(request, (0, Utils_1.readEjectData)()?.nodeEject)?.url ?? url;
|
|
498
|
-
}
|
|
499
|
-
exports.replaceRequest = replaceRequest;
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.buildServiceWorker = void 0;
|
|
7
|
-
const SwppRules_1 = require("./SwppRules");
|
|
8
|
-
const Utils_1 = require("./Utils");
|
|
9
|
-
const fs_1 = __importDefault(require("fs"));
|
|
10
|
-
const path_1 = __importDefault(require("path"));
|
|
11
|
-
/**
|
|
12
|
-
* 构建 sw
|
|
13
|
-
*
|
|
14
|
-
* + **执行该函数前必须调用过 [loadRules]**
|
|
15
|
-
* + **执行该函数前必须调用过 [calcEjectValues]**
|
|
16
|
-
*/
|
|
17
|
-
function buildServiceWorker() {
|
|
18
|
-
const rules = (0, SwppRules_1.readRules)();
|
|
19
|
-
const eject = (0, Utils_1.readEjectData)();
|
|
20
|
-
const { modifyRequest, fetchFile, getRaceUrls, getSpareUrls, blockRequest, config } = rules;
|
|
21
|
-
const serviceWorkerConfig = config.serviceWorker;
|
|
22
|
-
const templatePath = path_1.default.resolve('./', module.path, 'resources/sw-template.js');
|
|
23
|
-
// 获取拓展文件
|
|
24
|
-
let cache = (0, Utils_1.getSource)(rules, undefined, [
|
|
25
|
-
'cacheRules', 'modifyRequest', 'getRaceUrls', 'getSpareUrls', 'blockRequest', 'fetchFile',
|
|
26
|
-
...('external' in rules && Array.isArray(rules.external) ? rules.external : [])
|
|
27
|
-
], true) + '\n';
|
|
28
|
-
if (!fetchFile) {
|
|
29
|
-
if (getRaceUrls)
|
|
30
|
-
cache += JS_CODE_GET_CDN_LIST;
|
|
31
|
-
else if (getSpareUrls)
|
|
32
|
-
cache += JS_CODE_GET_SPARE_URLS;
|
|
33
|
-
else
|
|
34
|
-
cache += JS_CODE_DEF_FETCH_FILE;
|
|
35
|
-
}
|
|
36
|
-
if (!getSpareUrls)
|
|
37
|
-
cache += `\nconst getSpareUrls = _ => {}`;
|
|
38
|
-
if ('afterJoin' in rules)
|
|
39
|
-
cache += `(${(0, Utils_1.getSource)(rules['afterJoin'])})()\n`;
|
|
40
|
-
if ('afterTheme' in rules)
|
|
41
|
-
cache += `(${(0, Utils_1.getSource)(rules['afterTheme'])})()\n`;
|
|
42
|
-
const keyword = "const { cacheRules, fetchFile, getRaceUrls } = require('../sw-rules')";
|
|
43
|
-
// noinspection JSUnresolvedVariable
|
|
44
|
-
let content = fs_1.default.readFileSync(templatePath, 'utf8')
|
|
45
|
-
.replaceAll("// [insertion site] values", eject?.strValue ?? '')
|
|
46
|
-
.replaceAll(keyword, cache)
|
|
47
|
-
.replaceAll("'@$$[escape]'", (serviceWorkerConfig.escape).toString())
|
|
48
|
-
.replaceAll("'@$$[cacheName]'", `'${serviceWorkerConfig.cacheName}'`);
|
|
49
|
-
if (modifyRequest) {
|
|
50
|
-
content = content.replaceAll('// [modifyRequest call]', `
|
|
51
|
-
const modify = modifyRequest(request)
|
|
52
|
-
if (modify) request = modify
|
|
53
|
-
`).replaceAll('// [modifyRequest else-if]', `
|
|
54
|
-
else if (modify) event.respondWith(fetch(request))
|
|
55
|
-
`);
|
|
56
|
-
}
|
|
57
|
-
if (blockRequest) {
|
|
58
|
-
content = content.replace('// [blockRequest call]', `
|
|
59
|
-
if (blockRequest(url))
|
|
60
|
-
return event.respondWith(new Response(null, {status: 208}))
|
|
61
|
-
`);
|
|
62
|
-
}
|
|
63
|
-
// noinspection JSUnresolvedVariable
|
|
64
|
-
if (serviceWorkerConfig.debug) {
|
|
65
|
-
content = content.replaceAll('// [debug delete]', `
|
|
66
|
-
console.debug(\`delete cache: \${url}\`)
|
|
67
|
-
`).replaceAll('// [debug put]', `
|
|
68
|
-
console.debug(\`put cache: \${key}\`)
|
|
69
|
-
`).replaceAll('// [debug message]', `
|
|
70
|
-
console.debug(\`receive: \${event.data}\`)
|
|
71
|
-
`).replaceAll('// [debug escape]', `
|
|
72
|
-
console.debug(\`escape: \${aid}\`)
|
|
73
|
-
`);
|
|
74
|
-
}
|
|
75
|
-
return content;
|
|
76
|
-
}
|
|
77
|
-
exports.buildServiceWorker = buildServiceWorker;
|
|
78
|
-
// 缺省的 fetchFile 函数的代码
|
|
79
|
-
const JS_CODE_DEF_FETCH_FILE = `
|
|
80
|
-
const fetchFile = (request, banCache) => fetch(request, {
|
|
81
|
-
cache: banCache ? "no-store" : "default",
|
|
82
|
-
mode: 'cors',
|
|
83
|
-
credentials: 'same-origin'
|
|
84
|
-
})
|
|
85
|
-
`;
|
|
86
|
-
// getRaceUrls 函数的代码
|
|
87
|
-
const JS_CODE_GET_CDN_LIST = `
|
|
88
|
-
const fetchFile = (request, banCache) => {
|
|
89
|
-
const fetchArgs = {
|
|
90
|
-
cache: banCache ? 'no-store' : 'default',
|
|
91
|
-
mode: 'cors',
|
|
92
|
-
credentials: 'same-origin'
|
|
93
|
-
}
|
|
94
|
-
const list = getRaceUrls(request.url)
|
|
95
|
-
if (!list || !Promise.any) return fetch(request, fetchArgs)
|
|
96
|
-
const res = list.map(url => new Request(url, request))
|
|
97
|
-
const controllers = []
|
|
98
|
-
return Promise.any(res.map(
|
|
99
|
-
(it, index) => fetch(it, Object.assign(
|
|
100
|
-
{signal: (controllers[index] = new AbortController()).signal},
|
|
101
|
-
fetchArgs
|
|
102
|
-
)).then(response => checkResponse(response) ? {index, response} : Promise.reject())
|
|
103
|
-
)).then(it => {
|
|
104
|
-
for (let i in controllers) {
|
|
105
|
-
if (i != it.index) controllers[i].abort()
|
|
106
|
-
}
|
|
107
|
-
return it.response
|
|
108
|
-
})
|
|
109
|
-
}
|
|
110
|
-
`;
|
|
111
|
-
// getSpareUrls 函数的代码
|
|
112
|
-
const JS_CODE_GET_SPARE_URLS = `
|
|
113
|
-
const fetchFile = (request, banCache, spare = null) => {
|
|
114
|
-
const fetchArgs = {
|
|
115
|
-
cache: banCache ? 'no-store' : 'default',
|
|
116
|
-
mode: 'cors',
|
|
117
|
-
credentials: 'same-origin'
|
|
118
|
-
}
|
|
119
|
-
if (!spare) spare = getSpareUrls(request.url)
|
|
120
|
-
if (!spare) return fetch(request, fetchArgs)
|
|
121
|
-
const list = spare.list
|
|
122
|
-
const controllers = []
|
|
123
|
-
let error = 0
|
|
124
|
-
return new Promise((resolve, reject) => {
|
|
125
|
-
const pull = () => {
|
|
126
|
-
const flag = controllers.length
|
|
127
|
-
if (flag === list.length) return
|
|
128
|
-
const plusError = () => {
|
|
129
|
-
if (++error === list.length) reject(\`请求 \${request.url} 失败\`)
|
|
130
|
-
else if (flag + 1 === controllers.length) {
|
|
131
|
-
clearTimeout(controllers[flag].id)
|
|
132
|
-
pull()
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
controllers.push({
|
|
136
|
-
ctrl: new AbortController(),
|
|
137
|
-
id: setTimeout(pull, spare.timeout)
|
|
138
|
-
})
|
|
139
|
-
fetch(new Request(list[flag], request), fetchArgs).then(response => {
|
|
140
|
-
if (checkResponse(response)) {
|
|
141
|
-
for (let i in controllers) {
|
|
142
|
-
if (i !== flag) controllers[i].ctrl.abort()
|
|
143
|
-
clearTimeout(controllers[i].id)
|
|
144
|
-
}
|
|
145
|
-
resolve(response)
|
|
146
|
-
} else plusError()
|
|
147
|
-
}).catch(plusError)
|
|
148
|
-
}
|
|
149
|
-
pull()
|
|
150
|
-
})
|
|
151
|
-
}
|
|
152
|
-
`;
|
package/dist/ts/SwppConfig.js
DELETED