swpp-backends 2.0.9 → 2.1.1

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/README.md CHANGED
@@ -1,3 +1,5 @@
1
+ ![swpp](./swpp.jpg)
2
+
1
3
  ## 欢迎使用 SwppBackends
2
4
 
3
5
  swpp-backends(以下简称 swpp)插件的功能是为网站生成一个高度可用的 ServiceWorker(以下简称 SW),为网站优化二次加载、提供离线体验、提高可靠性,并为此附带了一些其它的功能。
@@ -30,6 +30,7 @@ function buildServiceWorker() {
30
30
  ...('external' in rules && Array.isArray(rules.external) ? rules.external : [])
31
31
  ], true) + '\n';
32
32
  if (!fetchFile) {
33
+ const { JS_CODE_GET_CDN_LIST, JS_CODE_GET_SPARE_URLS, JS_CODE_DEF_FETCH_FILE } = require('./resources/sw-fetch.js');
33
34
  if (getRaceUrls)
34
35
  cache += JS_CODE_GET_CDN_LIST;
35
36
  else if (getSpareUrls)
@@ -53,9 +54,12 @@ function buildServiceWorker() {
53
54
  if (modifyRequest) {
54
55
  content = content.replaceAll('// [modifyRequest call]', `
55
56
  const modify = modifyRequest(request)
56
- if (modify) request = modify
57
+ if (modify) {
58
+ request = modify
59
+ url = new URL(request.url)
60
+ }
57
61
  `).replaceAll('// [modifyRequest else-if]', `
58
- else if (modify) event.respondWith(fetch(request))
62
+ else if (modify) handleFetch(fetchFile(request, false))
59
63
  `);
60
64
  }
61
65
  if (blockRequest) {
@@ -79,91 +83,3 @@ function buildServiceWorker() {
79
83
  return content;
80
84
  }
81
85
  exports.buildServiceWorker = buildServiceWorker;
82
- // 缺省的 fetchFile 函数的代码
83
- const JS_CODE_DEF_FETCH_FILE = `
84
- const fetchFile = (request, banCache) => fetch(request, {
85
- cache: banCache ? "no-store" : "default",
86
- mode: 'cors',
87
- credentials: 'same-origin'
88
- })
89
- `;
90
- // getRaceUrls 函数的代码
91
- const JS_CODE_GET_CDN_LIST = `
92
- const fetchFile = (request, banCache) => {
93
- const fetchArgs = {
94
- cache: banCache ? 'no-store' : 'default',
95
- mode: 'cors',
96
- credentials: 'same-origin'
97
- }
98
- const list = getRaceUrls(request.url)
99
- if (!list || !Promise.any) return fetch(request, fetchArgs)
100
- const res = list.map(url => new Request(url, request))
101
- const controllers = []
102
- return Promise.any(res.map(
103
- (it, index) => fetch(it, Object.assign(
104
- {signal: (controllers[index] = new AbortController()).signal},
105
- fetchArgs
106
- )).then(response => checkResponse(response) ? {index, response} : Promise.reject())
107
- )).then(it => {
108
- for (let i in controllers) {
109
- if (i != it.index) controllers[i].abort()
110
- }
111
- return it.response
112
- })
113
- }
114
- `;
115
- // getSpareUrls 函数的代码
116
- const JS_CODE_GET_SPARE_URLS = `
117
- const fetchFile = (request, banCache, spare = null) => {
118
- const fetchArgs = {
119
- cache: banCache ? 'no-store' : 'default',
120
- mode: 'cors',
121
- credentials: 'same-origin'
122
- }
123
- if (!spare) {
124
- spare = getSpareUrls(request.url)
125
- if (!spare) return fetch(request, fetchArgs)
126
- }
127
- const list = spare.list
128
- const controllers = new Array(list.length)
129
- const startFetch =
130
- index => fetch(
131
- new Request(list[index], request),
132
- Object.assign({
133
- signal: (controllers[index] = new AbortController()).signal
134
- }, fetchArgs)
135
- ).then(response => checkResponse(response) ? {r: response, i: index} : Promise.reject())
136
- return new Promise((resolve, reject) => {
137
- let flag = true
138
- const startAll = () => {
139
- flag = false
140
- Promise.any([
141
- first,
142
- ...Array.from({
143
- length: list.length - 1
144
- }, (_, index) => index + 1).map(index => startFetch(index))
145
- ]).then(res => {
146
- for (let i = 0; i !== list.length; ++i) {
147
- if (i !== res.i)
148
- controllers[i].abort()
149
- }
150
- resolve(res.r)
151
- }).catch(() => reject(\`请求 \${request.url} 失败\`))
152
- }
153
- const id = setTimeout(startAll, spare.timeout)
154
- const first = startFetch(0)
155
- .then(res => {
156
- if (flag) {
157
- clearTimeout(id)
158
- resolve(res.r)
159
- }
160
- }).catch(() => {
161
- if (flag) {
162
- clearTimeout(id)
163
- startAll()
164
- }
165
- return Promise.reject()
166
- })
167
- })
168
- }
169
- `;
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ const VersionAnalyzer_1 = require("./VersionAnalyzer");
10
10
  const DomBuilder_1 = require("./DomBuilder");
11
11
  // noinspection JSUnusedGlobalSymbols
12
12
  exports.default = {
13
- version: '2.0.9',
13
+ version: '2.1.1',
14
14
  cache: {
15
15
  readEjectData: Utils_1.readEjectData, readUpdateJson: Variant_1.readUpdateJson,
16
16
  readRules: Variant_1.readRules, readMergeVersionMap: Variant_1.readMergeVersionMap,
@@ -0,0 +1,92 @@
1
+ /** @type function */
2
+ let getRaceUrls, checkResponse, getSpareUrls
3
+
4
+ module.exports.JS_CODE_DEF_FETCH_FILE = 'const fetchFile = ' + (
5
+ (request, banCache) => fetch(request, {
6
+ cache: banCache ? "no-store" : "default",
7
+ mode: 'cors',
8
+ credentials: 'same-origin'
9
+ })
10
+ ).toString()
11
+
12
+ module.exports.JS_CODE_GET_CDN_LIST= 'const fetchFile = ' + (
13
+ (request, banCache) => {
14
+ const fetchArgs = {
15
+ cache: banCache ? 'no-store' : 'default',
16
+ mode: 'cors',
17
+ credentials: 'same-origin'
18
+ }
19
+ const list = getRaceUrls(request.url)
20
+ if (!list || !Promise.any) return fetch(request, fetchArgs)
21
+ const res = list.map(url => new Request(url, request))
22
+ const controllers = []
23
+ // noinspection JSCheckFunctionSignatures
24
+ return Promise.any(res.map(
25
+ (it, index) => fetch(it, Object.assign(
26
+ {signal: (controllers[index] = new AbortController()).signal},
27
+ fetchArgs
28
+ )).then(response => checkResponse(response) ? {index, response} : Promise.reject())
29
+ )).then(it => {
30
+ for (let i in controllers) {
31
+ if (i !== it.index) controllers[i].abort()
32
+ }
33
+ return it.response
34
+ })
35
+ }
36
+ ).toString()
37
+
38
+ module.exports.JS_CODE_GET_SPARE_URLS = 'const fetchFile = ' + (
39
+ (request, banCache, spare = null) => {
40
+ const fetchArgs = {
41
+ cache: banCache ? 'no-store' : 'default',
42
+ mode: 'cors',
43
+ credentials: 'same-origin'
44
+ }
45
+ if (!spare) {
46
+ spare = getSpareUrls(request.url)
47
+ if (!spare) return fetch(request, fetchArgs)
48
+ }
49
+ const list = spare.list
50
+ const controllers = new Array(list.length)
51
+ // noinspection JSCheckFunctionSignatures
52
+ const startFetch =
53
+ index => fetch(
54
+ new Request(list[index], request),
55
+ Object.assign({
56
+ signal: (controllers[index] = new AbortController()).signal
57
+ }, fetchArgs)
58
+ ).then(response => checkResponse(response) ? {r: response, i: index} : Promise.reject())
59
+ return new Promise((resolve, reject) => {
60
+ let flag = true
61
+ const startAll = () => {
62
+ flag = false
63
+ Promise.any([
64
+ first,
65
+ ...Array.from({
66
+ length: list.length - 1
67
+ }, (_, index) => index + 1).map(index => startFetch(index))
68
+ ]).then(res => {
69
+ for (let i = 0; i !== list.length; ++i) {
70
+ if (i !== res.i)
71
+ controllers[i].abort()
72
+ }
73
+ resolve(res.r)
74
+ }).catch(() => reject(`请求 ${request.url} 失败`))
75
+ }
76
+ const id = setTimeout(startAll, spare.timeout)
77
+ const first = startFetch(0)
78
+ .then(res => {
79
+ if (flag) {
80
+ clearTimeout(id)
81
+ resolve(res.r)
82
+ }
83
+ }).catch(() => {
84
+ if (flag) {
85
+ clearTimeout(id)
86
+ startAll()
87
+ }
88
+ return Promise.reject()
89
+ })
90
+ })
91
+ }
92
+ ).toString()
@@ -63,33 +63,65 @@
63
63
  )).then(list => list.filter(it => it))
64
64
  )
65
65
 
66
+ /**
67
+ * 缓存列表
68
+ * @type {Map<string, {s, e}[]>}
69
+ */
70
+ const cacheMap = new Map()
71
+
66
72
  self.addEventListener('fetch', event => {
67
73
  let request = event.request
74
+ let url = new URL(request.url)
75
+ // [blockRequest call]
68
76
  if (request.method !== 'GET' || !request.url.startsWith('http')) return
69
77
  // [modifyRequest call]
70
- const url = new URL(request.url)
71
- // [blockRequest call]
78
+ let cacheKey = url.hostname + url.pathname + url.search
79
+ let cache = cacheMap.get(cacheKey)
80
+ if (cache) {
81
+ return event.respondWith(
82
+ new Promise((resolve, reject) => {
83
+ cacheMap.get(cacheKey).push({s: resolve, e: reject})
84
+ })
85
+ )
86
+ }
87
+ cacheMap.set(cacheKey, cache = [])
88
+ /** 处理拉取 */
89
+ const handleFetch = promise =>
90
+ event.respondWith(promise.then(response => {
91
+ for (let item of cache) {
92
+ item.s(response.clone())
93
+ }
94
+ }).catch(err => {
95
+ for (let item of cache) {
96
+ item.e(err)
97
+ }
98
+ }).then(() => {
99
+ cacheMap.delete(cacheKey)
100
+ return promise
101
+ }))
72
102
  const cacheRule = findCache(url)
73
103
  if (cacheRule) {
74
104
  let key = `https://${url.host}${url.pathname}`
75
105
  if (key.endsWith('/index.html')) key = key.substring(0, key.length - 10)
76
106
  if (cacheRule.search) key += url.search
77
- event.respondWith(caches.match(key)
78
- .then(cache => cache ?? fetchFile(request, true)
79
- .then(response => {
80
- if (checkResponse(response)) {
81
- const clone = response.clone()
82
- caches.open(CACHE_NAME).then(it => it.put(key, clone))
83
- // [debug put]
84
- }
85
- return response
86
- })
107
+ handleFetch(
108
+ caches.match(key).then(
109
+ cache => cache ?? fetchFile(request, true)
110
+ .then(response => {
111
+ if (checkResponse(response)) {
112
+ const clone = response.clone()
113
+ caches.open(CACHE_NAME).then(it => it.put(key, clone))
114
+ // [debug put]
115
+ }
116
+ return response
117
+ })
87
118
  )
88
119
  )
89
120
  } else {
90
121
  const spare = getSpareUrls(request.url)
91
- if (spare) event.respondWith(fetchFile(request, false, spare))
122
+ if (spare) handleFetch(fetchFile(request, false, spare))
92
123
  // [modifyRequest else-if]
124
+ else handleFetch(fetch(request))
93
125
  }
94
126
  })
95
127
 
@@ -106,8 +138,11 @@
106
138
  )
107
139
  })
108
140
 
109
- /** 判断指定url击中了哪一种缓存,都没有击中则返回null */
110
- function findCache(url) {
141
+ /**
142
+ * 判断指定 url 击中了哪一种缓存,都没有击中则返回 null
143
+ * @param url {URL}
144
+ */
145
+ const findCache = url => {
111
146
  if (url.hostname === 'localhost') return
112
147
  for (let key in cacheRules) {
113
148
  const value = cacheRules[key]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "swpp-backends",
3
- "version": "2.0.9",
3
+ "version": "2.1.1",
4
4
  "main": "dist/index.js",
5
5
  "typings": "types/index.d.ts",
6
6
  "description": "Generate a powerful ServiceWorker for your website.",