@serwist/precaching 9.0.0-preview.0 → 9.0.0-preview.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/dist/index.js +43 -427
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -3,15 +3,7 @@ import { copyResponse } from '@serwist/core';
|
|
|
3
3
|
import { Strategy } from '@serwist/strategies';
|
|
4
4
|
import { Route, registerRoute } from '@serwist/routing';
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
* A `@serwist/strategies.Strategy` implementation
|
|
8
|
-
* specifically designed to work with
|
|
9
|
-
* `@serwist/precaching.PrecacheController`
|
|
10
|
-
* to both cache and fetch precached assets.
|
|
11
|
-
*
|
|
12
|
-
* Note: an instance of this class is created automatically when creating a
|
|
13
|
-
* `PrecacheController`; it's generally not necessary to create this yourself.
|
|
14
|
-
*/ class PrecacheStrategy extends Strategy {
|
|
6
|
+
class PrecacheStrategy extends Strategy {
|
|
15
7
|
_fallbackToNetwork;
|
|
16
8
|
static defaultPrecacheCacheabilityPlugin = {
|
|
17
9
|
async cacheWillUpdate ({ response }) {
|
|
@@ -26,41 +18,25 @@ import { Route, registerRoute } from '@serwist/routing';
|
|
|
26
18
|
return response.redirected ? await copyResponse(response) : response;
|
|
27
19
|
}
|
|
28
20
|
};
|
|
29
|
-
|
|
30
|
-
* @param options
|
|
31
|
-
*/ constructor(options = {}){
|
|
21
|
+
constructor(options = {}){
|
|
32
22
|
options.cacheName = privateCacheNames.getPrecacheName(options.cacheName);
|
|
33
23
|
super(options);
|
|
34
24
|
this._fallbackToNetwork = options.fallbackToNetwork === false ? false : true;
|
|
35
|
-
// Redirected responses cannot be used to satisfy a navigation request, so
|
|
36
|
-
// any redirected response must be "copied" rather than cloned, so the new
|
|
37
|
-
// response doesn't contain the `redirected` flag. See:
|
|
38
|
-
// https://bugs.chromium.org/p/chromium/issues/detail?id=669363&desc=2#c1
|
|
39
25
|
this.plugins.push(PrecacheStrategy.copyRedirectedCacheableResponsesPlugin);
|
|
40
26
|
}
|
|
41
|
-
|
|
42
|
-
* @private
|
|
43
|
-
* @param request A request to run this strategy for.
|
|
44
|
-
* @param handler The event that triggered the request.
|
|
45
|
-
* @returns
|
|
46
|
-
*/ async _handle(request, handler) {
|
|
27
|
+
async _handle(request, handler) {
|
|
47
28
|
const response = await handler.cacheMatch(request);
|
|
48
29
|
if (response) {
|
|
49
30
|
return response;
|
|
50
31
|
}
|
|
51
|
-
// If this is an `install` event for an entry that isn't already cached,
|
|
52
|
-
// then populate the cache.
|
|
53
32
|
if (handler.event && handler.event.type === "install") {
|
|
54
33
|
return await this._handleInstall(request, handler);
|
|
55
34
|
}
|
|
56
|
-
// Getting here means something went wrong. An entry that should have been
|
|
57
|
-
// precached wasn't found in the cache.
|
|
58
35
|
return await this._handleFetch(request, handler);
|
|
59
36
|
}
|
|
60
37
|
async _handleFetch(request, handler) {
|
|
61
38
|
let response = undefined;
|
|
62
39
|
const params = handler.params || {};
|
|
63
|
-
// Fallback to the network if we're configured to do so.
|
|
64
40
|
if (this._fallbackToNetwork) {
|
|
65
41
|
if (process.env.NODE_ENV !== "production") {
|
|
66
42
|
logger.warn(`The precached response for ${getFriendlyURL(request.url)} in ${this.cacheName} was not found. Falling back to the network.`);
|
|
@@ -68,18 +44,9 @@ import { Route, registerRoute } from '@serwist/routing';
|
|
|
68
44
|
const integrityInManifest = params.integrity;
|
|
69
45
|
const integrityInRequest = request.integrity;
|
|
70
46
|
const noIntegrityConflict = !integrityInRequest || integrityInRequest === integrityInManifest;
|
|
71
|
-
// Do not add integrity if the original request is no-cors
|
|
72
|
-
// See https://github.com/GoogleChrome/workbox/issues/3096
|
|
73
47
|
response = await handler.fetch(new Request(request, {
|
|
74
48
|
integrity: request.mode !== "no-cors" ? integrityInRequest || integrityInManifest : undefined
|
|
75
49
|
}));
|
|
76
|
-
// It's only "safe" to repair the cache if we're using SRI to guarantee
|
|
77
|
-
// that the response matches the precache manifest's expectations,
|
|
78
|
-
// and there's either a) no integrity property in the incoming request
|
|
79
|
-
// or b) there is an integrity, and it matches the precache manifest.
|
|
80
|
-
// See https://github.com/GoogleChrome/workbox/issues/2858
|
|
81
|
-
// Also if the original request users no-cors we don't use integrity.
|
|
82
|
-
// See https://github.com/GoogleChrome/workbox/issues/3096
|
|
83
50
|
if (integrityInManifest && noIntegrityConflict && request.mode !== "no-cors") {
|
|
84
51
|
this._useDefaultCacheabilityPluginIfNeeded();
|
|
85
52
|
const wasCached = await handler.cachePut(request, response.clone());
|
|
@@ -90,8 +57,6 @@ import { Route, registerRoute } from '@serwist/routing';
|
|
|
90
57
|
}
|
|
91
58
|
}
|
|
92
59
|
} else {
|
|
93
|
-
// This shouldn't normally happen, but there are edge cases:
|
|
94
|
-
// https://github.com/GoogleChrome/workbox/issues/1441
|
|
95
60
|
throw new SerwistError("missing-precache-entry", {
|
|
96
61
|
cacheName: this.cacheName,
|
|
97
62
|
url: request.url
|
|
@@ -99,8 +64,6 @@ import { Route, registerRoute } from '@serwist/routing';
|
|
|
99
64
|
}
|
|
100
65
|
if (process.env.NODE_ENV !== "production") {
|
|
101
66
|
const cacheKey = params.cacheKey || await handler.getCacheKey(request, "read");
|
|
102
|
-
// Serwist is going to handle the route.
|
|
103
|
-
// print the routing details to the console.
|
|
104
67
|
logger.groupCollapsed(`Precaching is responding to: ${getFriendlyURL(request.url)}`);
|
|
105
68
|
logger.log(`Serving the precached url: ${getFriendlyURL(cacheKey instanceof Request ? cacheKey.url : cacheKey)}`);
|
|
106
69
|
logger.groupCollapsed("View request details here.");
|
|
@@ -116,12 +79,8 @@ import { Route, registerRoute } from '@serwist/routing';
|
|
|
116
79
|
async _handleInstall(request, handler) {
|
|
117
80
|
this._useDefaultCacheabilityPluginIfNeeded();
|
|
118
81
|
const response = await handler.fetch(request);
|
|
119
|
-
// Make sure we defer cachePut() until after we know the response
|
|
120
|
-
// should be cached; see https://github.com/GoogleChrome/workbox/issues/2737
|
|
121
82
|
const wasCached = await handler.cachePut(request, response.clone());
|
|
122
83
|
if (!wasCached) {
|
|
123
|
-
// Throwing here will lead to the `install` handler failing, which
|
|
124
|
-
// we want to do if *any* of the responses aren't safe to cache.
|
|
125
84
|
throw new SerwistError("bad-precaching-response", {
|
|
126
85
|
url: request.url,
|
|
127
86
|
status: response.status
|
|
@@ -129,41 +88,13 @@ import { Route, registerRoute } from '@serwist/routing';
|
|
|
129
88
|
}
|
|
130
89
|
return response;
|
|
131
90
|
}
|
|
132
|
-
|
|
133
|
-
* This method is complex, as there a number of things to account for:
|
|
134
|
-
*
|
|
135
|
-
* The `plugins` array can be set at construction, and/or it might be added to
|
|
136
|
-
* to at any time before the strategy is used.
|
|
137
|
-
*
|
|
138
|
-
* At the time the strategy is used (i.e. during an `install` event), there
|
|
139
|
-
* needs to be at least one plugin that implements `cacheWillUpdate` in the
|
|
140
|
-
* array, other than `copyRedirectedCacheableResponsesPlugin`.
|
|
141
|
-
*
|
|
142
|
-
* - If this method is called and there are no suitable `cacheWillUpdate`
|
|
143
|
-
* plugins, we need to add `defaultPrecacheCacheabilityPlugin`.
|
|
144
|
-
*
|
|
145
|
-
* - If this method is called and there is exactly one `cacheWillUpdate`, then
|
|
146
|
-
* we don't have to do anything (this might be a previously added
|
|
147
|
-
* `defaultPrecacheCacheabilityPlugin`, or it might be a custom plugin).
|
|
148
|
-
*
|
|
149
|
-
* - If this method is called and there is more than one `cacheWillUpdate`,
|
|
150
|
-
* then we need to check if one is `defaultPrecacheCacheabilityPlugin`. If so,
|
|
151
|
-
* we need to remove it. (This situation is unlikely, but it could happen if
|
|
152
|
-
* the strategy is used multiple times, the first without a `cacheWillUpdate`,
|
|
153
|
-
* and then later on after manually adding a custom `cacheWillUpdate`.)
|
|
154
|
-
*
|
|
155
|
-
* See https://github.com/GoogleChrome/workbox/issues/2737 for more context.
|
|
156
|
-
*
|
|
157
|
-
* @private
|
|
158
|
-
*/ _useDefaultCacheabilityPluginIfNeeded() {
|
|
91
|
+
_useDefaultCacheabilityPluginIfNeeded() {
|
|
159
92
|
let defaultPluginIndex = null;
|
|
160
93
|
let cacheWillUpdatePluginCount = 0;
|
|
161
94
|
for (const [index, plugin] of this.plugins.entries()){
|
|
162
|
-
// Ignore the copy redirected plugin when determining what to do.
|
|
163
95
|
if (plugin === PrecacheStrategy.copyRedirectedCacheableResponsesPlugin) {
|
|
164
96
|
continue;
|
|
165
97
|
}
|
|
166
|
-
// Save the default plugin's index, in case it needs to be removed.
|
|
167
98
|
if (plugin === PrecacheStrategy.defaultPrecacheCacheabilityPlugin) {
|
|
168
99
|
defaultPluginIndex = index;
|
|
169
100
|
}
|
|
@@ -174,54 +105,28 @@ import { Route, registerRoute } from '@serwist/routing';
|
|
|
174
105
|
if (cacheWillUpdatePluginCount === 0) {
|
|
175
106
|
this.plugins.push(PrecacheStrategy.defaultPrecacheCacheabilityPlugin);
|
|
176
107
|
} else if (cacheWillUpdatePluginCount > 1 && defaultPluginIndex !== null) {
|
|
177
|
-
// Only remove the default plugin; multiple custom plugins are allowed.
|
|
178
108
|
this.plugins.splice(defaultPluginIndex, 1);
|
|
179
109
|
}
|
|
180
|
-
// Nothing needs to be done if cacheWillUpdatePluginCount is 1
|
|
181
110
|
}
|
|
182
111
|
}
|
|
183
112
|
|
|
184
|
-
|
|
185
|
-
Copyright 2020 Google LLC
|
|
186
|
-
|
|
187
|
-
Use of this source code is governed by an MIT-style
|
|
188
|
-
license that can be found in the LICENSE file or at
|
|
189
|
-
https://opensource.org/licenses/MIT.
|
|
190
|
-
*/ /**
|
|
191
|
-
* A plugin, designed to be used with PrecacheController, to translate URLs into
|
|
192
|
-
* the corresponding cache key, based on the current revision info.
|
|
193
|
-
*
|
|
194
|
-
* @private
|
|
195
|
-
*/ class PrecacheCacheKeyPlugin {
|
|
113
|
+
class PrecacheCacheKeyPlugin {
|
|
196
114
|
_precacheController;
|
|
197
115
|
constructor({ precacheController }){
|
|
198
116
|
this._precacheController = precacheController;
|
|
199
117
|
}
|
|
200
118
|
cacheKeyWillBeUsed = async ({ request, params })=>{
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
/* eslint-enable */ return cacheKey ? new Request(cacheKey, {
|
|
119
|
+
const cacheKey = params?.cacheKey || this._precacheController.getCacheKeyForURL(request.url);
|
|
120
|
+
return cacheKey ? new Request(cacheKey, {
|
|
204
121
|
headers: request.headers
|
|
205
122
|
}) : request;
|
|
206
123
|
};
|
|
207
124
|
}
|
|
208
125
|
|
|
209
|
-
|
|
210
|
-
Copyright 2020 Google LLC
|
|
211
|
-
|
|
212
|
-
Use of this source code is governed by an MIT-style
|
|
213
|
-
license that can be found in the LICENSE file or at
|
|
214
|
-
https://opensource.org/licenses/MIT.
|
|
215
|
-
*/ /**
|
|
216
|
-
* A plugin, designed to be used with PrecacheController, to determine the
|
|
217
|
-
* of assets that were updated (or not updated) during the install event.
|
|
218
|
-
*
|
|
219
|
-
* @private
|
|
220
|
-
*/ class PrecacheInstallReportPlugin {
|
|
126
|
+
class PrecacheInstallReportPlugin {
|
|
221
127
|
updatedURLs = [];
|
|
222
128
|
notUpdatedURLs = [];
|
|
223
129
|
handlerWillStart = async ({ request, state })=>{
|
|
224
|
-
// TODO: `state` should never be undefined...
|
|
225
130
|
if (state) {
|
|
226
131
|
state.originalRequest = request;
|
|
227
132
|
}
|
|
@@ -229,7 +134,6 @@ import { Route, registerRoute } from '@serwist/routing';
|
|
|
229
134
|
cachedResponseWillBeUsed = async ({ event, state, cachedResponse })=>{
|
|
230
135
|
if (event.type === "install") {
|
|
231
136
|
if (state?.originalRequest && state.originalRequest instanceof Request) {
|
|
232
|
-
// TODO: `state` should never be undefined...
|
|
233
137
|
const url = state.originalRequest.url;
|
|
234
138
|
if (cachedResponse) {
|
|
235
139
|
this.notUpdatedURLs.push(url);
|
|
@@ -242,23 +146,13 @@ import { Route, registerRoute } from '@serwist/routing';
|
|
|
242
146
|
};
|
|
243
147
|
}
|
|
244
148
|
|
|
245
|
-
// Name of the search parameter used to store revision info.
|
|
246
149
|
const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
247
|
-
|
|
248
|
-
* Converts a manifest entry into a versioned URL suitable for precaching.
|
|
249
|
-
*
|
|
250
|
-
* @param entry
|
|
251
|
-
* @returns A URL with versioning info.
|
|
252
|
-
*
|
|
253
|
-
* @private
|
|
254
|
-
*/ function createCacheKey(entry) {
|
|
150
|
+
function createCacheKey(entry) {
|
|
255
151
|
if (!entry) {
|
|
256
152
|
throw new SerwistError("add-to-cache-list-unexpected-type", {
|
|
257
153
|
entry
|
|
258
154
|
});
|
|
259
155
|
}
|
|
260
|
-
// If a precache manifest entry is a string, it's assumed to be a versioned
|
|
261
|
-
// URL, like '/app.abcd1234.js'. Return as-is.
|
|
262
156
|
if (typeof entry === "string") {
|
|
263
157
|
const urlObject = new URL(entry, location.href);
|
|
264
158
|
return {
|
|
@@ -272,8 +166,6 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
272
166
|
entry
|
|
273
167
|
});
|
|
274
168
|
}
|
|
275
|
-
// If there's just a URL and no revision, then it's also assumed to be a
|
|
276
|
-
// versioned URL.
|
|
277
169
|
if (!revision) {
|
|
278
170
|
const urlObject = new URL(url, location.href);
|
|
279
171
|
return {
|
|
@@ -281,8 +173,6 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
281
173
|
url: urlObject.href
|
|
282
174
|
};
|
|
283
175
|
}
|
|
284
|
-
// Otherwise, construct a properly versioned URL using the custom Serwist
|
|
285
|
-
// search parameter along with the revision info.
|
|
286
176
|
const cacheKeyURL = new URL(url, location.href);
|
|
287
177
|
const originalURL = new URL(url, location.href);
|
|
288
178
|
cacheKeyURL.searchParams.set(REVISION_SEARCH_PARAM, revision);
|
|
@@ -292,22 +182,14 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
292
182
|
};
|
|
293
183
|
}
|
|
294
184
|
|
|
295
|
-
|
|
296
|
-
* @param groupTitle
|
|
297
|
-
* @param deletedURLs
|
|
298
|
-
*
|
|
299
|
-
* @private
|
|
300
|
-
*/ const logGroup = (groupTitle, deletedURLs)=>{
|
|
185
|
+
const logGroup = (groupTitle, deletedURLs)=>{
|
|
301
186
|
logger.groupCollapsed(groupTitle);
|
|
302
187
|
for (const url of deletedURLs){
|
|
303
188
|
logger.log(url);
|
|
304
189
|
}
|
|
305
190
|
logger.groupEnd();
|
|
306
191
|
};
|
|
307
|
-
|
|
308
|
-
* @param deletedURLs
|
|
309
|
-
* @private
|
|
310
|
-
*/ function printCleanupDetails(deletedURLs) {
|
|
192
|
+
function printCleanupDetails(deletedURLs) {
|
|
311
193
|
const deletionCount = deletedURLs.length;
|
|
312
194
|
if (deletionCount > 0) {
|
|
313
195
|
logger.groupCollapsed(`During precaching cleanup, ${deletionCount} cached request${deletionCount === 1 ? " was" : "s were"} deleted.`);
|
|
@@ -316,12 +198,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
316
198
|
}
|
|
317
199
|
}
|
|
318
200
|
|
|
319
|
-
|
|
320
|
-
* @param groupTitle
|
|
321
|
-
* @param urls
|
|
322
|
-
*
|
|
323
|
-
* @private
|
|
324
|
-
*/ function _nestedGroup(groupTitle, urls) {
|
|
201
|
+
function _nestedGroup(groupTitle, urls) {
|
|
325
202
|
if (urls.length === 0) {
|
|
326
203
|
return;
|
|
327
204
|
}
|
|
@@ -331,11 +208,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
331
208
|
}
|
|
332
209
|
logger.groupEnd();
|
|
333
210
|
}
|
|
334
|
-
|
|
335
|
-
* @param urlsToPrecache
|
|
336
|
-
* @param urlsAlreadyPrecached
|
|
337
|
-
* @private
|
|
338
|
-
*/ function printInstallDetails(urlsToPrecache, urlsAlreadyPrecached) {
|
|
211
|
+
function printInstallDetails(urlsToPrecache, urlsAlreadyPrecached) {
|
|
339
212
|
const precachedCount = urlsToPrecache.length;
|
|
340
213
|
const alreadyPrecachedCount = urlsAlreadyPrecached.length;
|
|
341
214
|
if (precachedCount || alreadyPrecachedCount) {
|
|
@@ -350,19 +223,13 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
350
223
|
}
|
|
351
224
|
}
|
|
352
225
|
|
|
353
|
-
|
|
354
|
-
* Performs efficient precaching of assets.
|
|
355
|
-
*/ class PrecacheController {
|
|
226
|
+
class PrecacheController {
|
|
356
227
|
_installAndActiveListenersAdded;
|
|
357
228
|
_strategy;
|
|
358
229
|
_urlsToCacheKeys = new Map();
|
|
359
230
|
_urlsToCacheModes = new Map();
|
|
360
231
|
_cacheKeysToIntegrities = new Map();
|
|
361
|
-
|
|
362
|
-
* Create a new PrecacheController.
|
|
363
|
-
*
|
|
364
|
-
* @param options
|
|
365
|
-
*/ constructor({ cacheName, plugins = [], fallbackToNetwork = true } = {}){
|
|
232
|
+
constructor({ cacheName, plugins = [], fallbackToNetwork = true } = {}){
|
|
366
233
|
this._strategy = new PrecacheStrategy({
|
|
367
234
|
cacheName: privateCacheNames.getPrecacheName(cacheName),
|
|
368
235
|
plugins: [
|
|
@@ -373,25 +240,13 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
373
240
|
],
|
|
374
241
|
fallbackToNetwork
|
|
375
242
|
});
|
|
376
|
-
// Bind the install and activate methods to the instance.
|
|
377
243
|
this.install = this.install.bind(this);
|
|
378
244
|
this.activate = this.activate.bind(this);
|
|
379
245
|
}
|
|
380
|
-
|
|
381
|
-
* The strategy created by this controller and
|
|
382
|
-
* used to cache assets and respond to fetch events.
|
|
383
|
-
*/ get strategy() {
|
|
246
|
+
get strategy() {
|
|
384
247
|
return this._strategy;
|
|
385
248
|
}
|
|
386
|
-
|
|
387
|
-
* Adds items to the precache list, removing any duplicates and
|
|
388
|
-
* stores the files in the precache cache when the service
|
|
389
|
-
* worker installs.
|
|
390
|
-
*
|
|
391
|
-
* This method can be called multiple times.
|
|
392
|
-
*
|
|
393
|
-
* @param entries Array of entries to precache.
|
|
394
|
-
*/ precache(entries) {
|
|
249
|
+
precache(entries) {
|
|
395
250
|
this.addToCacheList(entries);
|
|
396
251
|
if (!this._installAndActiveListenersAdded) {
|
|
397
252
|
self.addEventListener("install", this.install);
|
|
@@ -399,12 +254,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
399
254
|
this._installAndActiveListenersAdded = true;
|
|
400
255
|
}
|
|
401
256
|
}
|
|
402
|
-
|
|
403
|
-
* This method will add items to the precache list, removing duplicates
|
|
404
|
-
* and ensuring the information is valid.
|
|
405
|
-
*
|
|
406
|
-
* @param entries Array of entries to precache.
|
|
407
|
-
*/ addToCacheList(entries) {
|
|
257
|
+
addToCacheList(entries) {
|
|
408
258
|
if (process.env.NODE_ENV !== "production") {
|
|
409
259
|
assert.isArray(entries, {
|
|
410
260
|
moduleName: "@serwist/precaching",
|
|
@@ -415,7 +265,6 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
415
265
|
}
|
|
416
266
|
const urlsToWarnAbout = [];
|
|
417
267
|
for (const entry of entries){
|
|
418
|
-
// See https://github.com/GoogleChrome/workbox/issues/2259
|
|
419
268
|
if (typeof entry === "string") {
|
|
420
269
|
urlsToWarnAbout.push(entry);
|
|
421
270
|
} else if (entry && entry.revision === undefined) {
|
|
@@ -442,8 +291,6 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
442
291
|
if (urlsToWarnAbout.length > 0) {
|
|
443
292
|
const warningMessage = `Serwist is precaching URLs without revision info: ${urlsToWarnAbout.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;
|
|
444
293
|
if (process.env.NODE_ENV === "production") {
|
|
445
|
-
// Use console directly to display this warning without bloating
|
|
446
|
-
// bundle sizes by pulling in all of the logger codebase in prod.
|
|
447
294
|
console.warn(warningMessage);
|
|
448
295
|
} else {
|
|
449
296
|
logger.warn(warningMessage);
|
|
@@ -451,23 +298,10 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
451
298
|
}
|
|
452
299
|
}
|
|
453
300
|
}
|
|
454
|
-
|
|
455
|
-
* Precaches new and updated assets. Call this method from the service worker
|
|
456
|
-
* install event.
|
|
457
|
-
*
|
|
458
|
-
* Note: this method calls `event.waitUntil()` for you, so you do not need
|
|
459
|
-
* to call it yourself in your event handlers.
|
|
460
|
-
*
|
|
461
|
-
* @param event
|
|
462
|
-
* @returns
|
|
463
|
-
*/ install(event) {
|
|
464
|
-
// waitUntil returns Promise<any>
|
|
465
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
301
|
+
install(event) {
|
|
466
302
|
return waitUntil(event, async ()=>{
|
|
467
303
|
const installReportPlugin = new PrecacheInstallReportPlugin();
|
|
468
304
|
this.strategy.plugins.push(installReportPlugin);
|
|
469
|
-
// Cache entries one at a time.
|
|
470
|
-
// See https://github.com/GoogleChrome/workbox/issues/2528
|
|
471
305
|
for (const [url, cacheKey] of this._urlsToCacheKeys){
|
|
472
306
|
const integrity = this._cacheKeysToIntegrities.get(cacheKey);
|
|
473
307
|
const cacheMode = this._urlsToCacheModes.get(url);
|
|
@@ -494,18 +328,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
494
328
|
};
|
|
495
329
|
});
|
|
496
330
|
}
|
|
497
|
-
|
|
498
|
-
* Deletes assets that are no longer present in the current precache manifest.
|
|
499
|
-
* Call this method from the service worker activate event.
|
|
500
|
-
*
|
|
501
|
-
* Note: this method calls `event.waitUntil()` for you, so you do not need
|
|
502
|
-
* to call it yourself in your event handlers.
|
|
503
|
-
*
|
|
504
|
-
* @param event
|
|
505
|
-
* @returns
|
|
506
|
-
*/ activate(event) {
|
|
507
|
-
// waitUntil returns Promise<any>
|
|
508
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
|
331
|
+
activate(event) {
|
|
509
332
|
return waitUntil(event, async ()=>{
|
|
510
333
|
const cache = await self.caches.open(this.strategy.cacheName);
|
|
511
334
|
const currentlyCachedRequests = await cache.keys();
|
|
@@ -525,61 +348,22 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
525
348
|
};
|
|
526
349
|
});
|
|
527
350
|
}
|
|
528
|
-
|
|
529
|
-
* Returns a mapping of a precached URL to the corresponding cache key, taking
|
|
530
|
-
* into account the revision information for the URL.
|
|
531
|
-
*
|
|
532
|
-
* @returns A URL to cache key mapping.
|
|
533
|
-
*/ getURLsToCacheKeys() {
|
|
351
|
+
getURLsToCacheKeys() {
|
|
534
352
|
return this._urlsToCacheKeys;
|
|
535
353
|
}
|
|
536
|
-
|
|
537
|
-
* Returns a list of all the URLs that have been precached by the current
|
|
538
|
-
* service worker.
|
|
539
|
-
*
|
|
540
|
-
* @returns The precached URLs.
|
|
541
|
-
*/ getCachedURLs() {
|
|
354
|
+
getCachedURLs() {
|
|
542
355
|
return [
|
|
543
356
|
...this._urlsToCacheKeys.keys()
|
|
544
357
|
];
|
|
545
358
|
}
|
|
546
|
-
|
|
547
|
-
* Returns the cache key used for storing a given URL. If that URL is
|
|
548
|
-
* unversioned, like `/index.html', then the cache key will be the original
|
|
549
|
-
* URL with a search parameter appended to it.
|
|
550
|
-
*
|
|
551
|
-
* @param url A URL whose cache key you want to look up.
|
|
552
|
-
* @returns The versioned URL that corresponds to a cache key
|
|
553
|
-
* for the original URL, or undefined if that URL isn't precached.
|
|
554
|
-
*/ getCacheKeyForURL(url) {
|
|
359
|
+
getCacheKeyForURL(url) {
|
|
555
360
|
const urlObject = new URL(url, location.href);
|
|
556
361
|
return this._urlsToCacheKeys.get(urlObject.href);
|
|
557
362
|
}
|
|
558
|
-
|
|
559
|
-
* @param url A cache key whose SRI you want to look up.
|
|
560
|
-
* @returns The subresource integrity associated with the cache key,
|
|
561
|
-
* or undefined if it's not set.
|
|
562
|
-
*/ getIntegrityForCacheKey(cacheKey) {
|
|
363
|
+
getIntegrityForCacheKey(cacheKey) {
|
|
563
364
|
return this._cacheKeysToIntegrities.get(cacheKey);
|
|
564
365
|
}
|
|
565
|
-
|
|
566
|
-
* This acts as a drop-in replacement for
|
|
567
|
-
* [`cache.match()`](https://developer.mozilla.org/en-US/docs/Web/API/Cache/match)
|
|
568
|
-
* with the following differences:
|
|
569
|
-
*
|
|
570
|
-
* - It knows what the name of the precache is, and only checks in that cache.
|
|
571
|
-
* - It allows you to pass in an "original" URL without versioning parameters,
|
|
572
|
-
* and it will automatically look up the correct cache key for the currently
|
|
573
|
-
* active revision of that URL.
|
|
574
|
-
*
|
|
575
|
-
* E.g., `matchPrecache('index.html')` will find the correct precached
|
|
576
|
-
* response for the currently active service worker, even if the actual cache
|
|
577
|
-
* key is `'/index.html?__WB_REVISION__=1234abcd'`.
|
|
578
|
-
*
|
|
579
|
-
* @param request The key (without revisioning parameters)
|
|
580
|
-
* to look up in the precache.
|
|
581
|
-
* @returns
|
|
582
|
-
*/ async matchPrecache(request) {
|
|
366
|
+
async matchPrecache(request) {
|
|
583
367
|
const url = request instanceof Request ? request.url : request;
|
|
584
368
|
const cacheKey = this.getCacheKeyForURL(url);
|
|
585
369
|
if (cacheKey) {
|
|
@@ -588,13 +372,7 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
588
372
|
}
|
|
589
373
|
return undefined;
|
|
590
374
|
}
|
|
591
|
-
|
|
592
|
-
* Returns a function that looks up `url` in the precache (taking into
|
|
593
|
-
* account revision information), and returns the corresponding `Response`.
|
|
594
|
-
*
|
|
595
|
-
* @param url The precached URL which will be used to lookup the response.
|
|
596
|
-
* @return
|
|
597
|
-
*/ createHandlerBoundToURL(url) {
|
|
375
|
+
createHandlerBoundToURL(url) {
|
|
598
376
|
const cacheKey = this.getCacheKeyForURL(url);
|
|
599
377
|
if (!cacheKey) {
|
|
600
378
|
throw new SerwistError("non-precached-url", {
|
|
@@ -613,62 +391,24 @@ const REVISION_SEARCH_PARAM = "__WB_REVISION__";
|
|
|
613
391
|
}
|
|
614
392
|
|
|
615
393
|
let precacheController;
|
|
616
|
-
|
|
617
|
-
* @returns
|
|
618
|
-
* @private
|
|
619
|
-
*/ const getOrCreatePrecacheController = ()=>{
|
|
394
|
+
const getOrCreatePrecacheController = ()=>{
|
|
620
395
|
if (!precacheController) {
|
|
621
396
|
precacheController = new PrecacheController();
|
|
622
397
|
}
|
|
623
398
|
return precacheController;
|
|
624
399
|
};
|
|
625
400
|
|
|
626
|
-
|
|
627
|
-
* `PrecacheFallbackPlugin` allows you to specify an "offline fallback"
|
|
628
|
-
* response to be used when a given strategy is unable to generate a response.
|
|
629
|
-
*
|
|
630
|
-
* It does this by intercepting the `handlerDidError` plugin callback
|
|
631
|
-
* and returning a precached response, taking the expected revision parameter
|
|
632
|
-
* into account automatically.
|
|
633
|
-
*
|
|
634
|
-
* Unless you explicitly pass in a `PrecacheController` instance to the
|
|
635
|
-
* constructor, the default instance will be used. Generally speaking, most
|
|
636
|
-
* developers will end up using the default.
|
|
637
|
-
*/ class PrecacheFallbackPlugin {
|
|
401
|
+
class PrecacheFallbackPlugin {
|
|
638
402
|
_fallbackURL;
|
|
639
403
|
_precacheController;
|
|
640
|
-
|
|
641
|
-
* Constructs a new PrecacheFallbackPlugin with the associated fallbackURL.
|
|
642
|
-
*
|
|
643
|
-
* @param config
|
|
644
|
-
*/ constructor({ fallbackURL, precacheController }){
|
|
404
|
+
constructor({ fallbackURL, precacheController }){
|
|
645
405
|
this._fallbackURL = fallbackURL;
|
|
646
406
|
this._precacheController = precacheController || getOrCreatePrecacheController();
|
|
647
407
|
}
|
|
648
|
-
|
|
649
|
-
* @returns The precache response for the fallback URL.
|
|
650
|
-
* @private
|
|
651
|
-
*/ handlerDidError = ()=>this._precacheController.matchPrecache(this._fallbackURL);
|
|
408
|
+
handlerDidError = ()=>this._precacheController.matchPrecache(this._fallbackURL);
|
|
652
409
|
}
|
|
653
410
|
|
|
654
|
-
|
|
655
|
-
Copyright 2018 Google LLC
|
|
656
|
-
|
|
657
|
-
Use of this source code is governed by an MIT-style
|
|
658
|
-
license that can be found in the LICENSE file or at
|
|
659
|
-
https://opensource.org/licenses/MIT.
|
|
660
|
-
*/ /**
|
|
661
|
-
* Removes any URL search parameters that should be ignored.
|
|
662
|
-
*
|
|
663
|
-
* @param urlObject The original URL.
|
|
664
|
-
* @param ignoreURLParametersMatching RegExps to test against
|
|
665
|
-
* each search parameter name. Matches mean that the search parameter should be
|
|
666
|
-
* ignored.
|
|
667
|
-
* @returns The URL with any ignored search parameters removed.
|
|
668
|
-
* @private
|
|
669
|
-
*/ function removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching = []) {
|
|
670
|
-
// Convert the iterable into an array at the start of the loop to make sure
|
|
671
|
-
// deletion doesn't mess up iteration.
|
|
411
|
+
function removeIgnoredSearchParams(urlObject, ignoreURLParametersMatching = []) {
|
|
672
412
|
for (const paramName of [
|
|
673
413
|
...urlObject.searchParams.keys()
|
|
674
414
|
]){
|
|
@@ -679,15 +419,7 @@ let precacheController;
|
|
|
679
419
|
return urlObject;
|
|
680
420
|
}
|
|
681
421
|
|
|
682
|
-
|
|
683
|
-
* Generator function that yields possible variations on the original URL to
|
|
684
|
-
* check, one at a time.
|
|
685
|
-
*
|
|
686
|
-
* @param url
|
|
687
|
-
* @param options
|
|
688
|
-
*
|
|
689
|
-
* @private
|
|
690
|
-
*/ function* generateURLVariations(url, { ignoreURLParametersMatching = [
|
|
422
|
+
function* generateURLVariations(url, { ignoreURLParametersMatching = [
|
|
691
423
|
/^utm_/,
|
|
692
424
|
/^fbclid$/
|
|
693
425
|
], directoryIndex = "index.html", cleanURLs = true, urlManipulation } = {}) {
|
|
@@ -716,18 +448,8 @@ let precacheController;
|
|
|
716
448
|
}
|
|
717
449
|
}
|
|
718
450
|
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
* `@serwist/precaching.PrecacheController`
|
|
722
|
-
* instance and uses it to match incoming requests and handle fetching
|
|
723
|
-
* responses from the precache.
|
|
724
|
-
*/ class PrecacheRoute extends Route {
|
|
725
|
-
/**
|
|
726
|
-
* @param precacheController A `PrecacheController`
|
|
727
|
-
* instance used to both match requests and respond to fetch events.
|
|
728
|
-
* @param options Options to control how requests are matched
|
|
729
|
-
* against the list of precached URLs.
|
|
730
|
-
*/ constructor(precacheController, options){
|
|
451
|
+
class PrecacheRoute extends Route {
|
|
452
|
+
constructor(precacheController, options){
|
|
731
453
|
const match = ({ request })=>{
|
|
732
454
|
const urlsToCacheKeys = precacheController.getURLsToCacheKeys();
|
|
733
455
|
for (const possibleURL of generateURLVariations(request.url, options)){
|
|
@@ -749,56 +471,19 @@ let precacheController;
|
|
|
749
471
|
}
|
|
750
472
|
}
|
|
751
473
|
|
|
752
|
-
|
|
753
|
-
* Adds plugins to the precaching strategy.
|
|
754
|
-
*
|
|
755
|
-
* @param plugins
|
|
756
|
-
*/ function addPlugins(plugins) {
|
|
474
|
+
function addPlugins(plugins) {
|
|
757
475
|
const precacheController = getOrCreatePrecacheController();
|
|
758
476
|
precacheController.strategy.plugins.push(...plugins);
|
|
759
477
|
}
|
|
760
478
|
|
|
761
|
-
|
|
762
|
-
* Add a `fetch` listener to the service worker that will
|
|
763
|
-
* respond to
|
|
764
|
-
* [network requests](https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests)
|
|
765
|
-
* with precached assets.
|
|
766
|
-
*
|
|
767
|
-
* Requests for assets that aren't precached, the `FetchEvent` will not be
|
|
768
|
-
* responded to, allowing the event to fall through to other `fetch` event
|
|
769
|
-
* listeners.
|
|
770
|
-
*
|
|
771
|
-
* @param options See the `@serwist/precaching.PrecacheRoute` options.
|
|
772
|
-
*/ function addRoute(options) {
|
|
479
|
+
function addRoute(options) {
|
|
773
480
|
const precacheController = getOrCreatePrecacheController();
|
|
774
481
|
const precacheRoute = new PrecacheRoute(precacheController, options);
|
|
775
482
|
registerRoute(precacheRoute);
|
|
776
483
|
}
|
|
777
484
|
|
|
778
|
-
/*
|
|
779
|
-
Copyright 2018 Google LLC
|
|
780
|
-
|
|
781
|
-
Use of this source code is governed by an MIT-style
|
|
782
|
-
license that can be found in the LICENSE file or at
|
|
783
|
-
https://opensource.org/licenses/MIT.
|
|
784
|
-
*/ // Give TypeScript the correct global.
|
|
785
485
|
const SUBSTRING_TO_FIND = "-precache-";
|
|
786
|
-
|
|
787
|
-
* Cleans up incompatible precaches that were created by older versions of
|
|
788
|
-
* Serwist, by a service worker registered under the current scope.
|
|
789
|
-
*
|
|
790
|
-
* This is meant to be called as part of the `activate` event.
|
|
791
|
-
*
|
|
792
|
-
* This should be safe to use as long as you don't include `substringToFind`
|
|
793
|
-
* (defaulting to `-precache-`) in your non-precache cache names.
|
|
794
|
-
*
|
|
795
|
-
* @param currentPrecacheName The cache name currently in use for
|
|
796
|
-
* precaching. This cache won't be deleted.
|
|
797
|
-
* @param substringToFind Cache names which include this
|
|
798
|
-
* substring will be deleted (excluding `currentPrecacheName`).
|
|
799
|
-
* @returns A list of all the cache names that were deleted.
|
|
800
|
-
* @private
|
|
801
|
-
*/ const deleteOutdatedCaches = async (currentPrecacheName, substringToFind = SUBSTRING_TO_FIND)=>{
|
|
486
|
+
const deleteOutdatedCaches = async (currentPrecacheName, substringToFind = SUBSTRING_TO_FIND)=>{
|
|
802
487
|
const cacheNames = await self.caches.keys();
|
|
803
488
|
const cacheNamesToDelete = cacheNames.filter((cacheName)=>{
|
|
804
489
|
return cacheName.includes(substringToFind) && cacheName.includes(self.registration.scope) && cacheName !== currentPrecacheName;
|
|
@@ -807,11 +492,7 @@ const SUBSTRING_TO_FIND = "-precache-";
|
|
|
807
492
|
return cacheNamesToDelete;
|
|
808
493
|
};
|
|
809
494
|
|
|
810
|
-
|
|
811
|
-
* Adds an `activate` event listener which will clean up incompatible
|
|
812
|
-
* precaches that were created by older versions of Serwist.
|
|
813
|
-
*/ function cleanupOutdatedCaches() {
|
|
814
|
-
// See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
|
|
495
|
+
function cleanupOutdatedCaches() {
|
|
815
496
|
self.addEventListener("activate", (event)=>{
|
|
816
497
|
const cacheName = privateCacheNames.getPrecacheName();
|
|
817
498
|
event.waitUntil(deleteOutdatedCaches(cacheName).then((cachesDeleted)=>{
|
|
@@ -824,92 +505,27 @@ const SUBSTRING_TO_FIND = "-precache-";
|
|
|
824
505
|
});
|
|
825
506
|
}
|
|
826
507
|
|
|
827
|
-
|
|
828
|
-
* Helper function that calls `PrecacheController#createHandlerBoundToURL`
|
|
829
|
-
* on the default `PrecacheController` instance.
|
|
830
|
-
*
|
|
831
|
-
* If you are creating your own `PrecacheController`, then call the
|
|
832
|
-
* `PrecacheController#createHandlerBoundToURL` on that instance,
|
|
833
|
-
* instead of using this function.
|
|
834
|
-
*
|
|
835
|
-
* @param url The precached URL which will be used to lookup the
|
|
836
|
-
* `Response`.
|
|
837
|
-
* @param fallbackToNetwork Whether to attempt to get the
|
|
838
|
-
* response from the network if there's a precache miss.
|
|
839
|
-
* @return
|
|
840
|
-
*/ function createHandlerBoundToURL(url) {
|
|
508
|
+
function createHandlerBoundToURL(url) {
|
|
841
509
|
const precacheController = getOrCreatePrecacheController();
|
|
842
510
|
return precacheController.createHandlerBoundToURL(url);
|
|
843
511
|
}
|
|
844
512
|
|
|
845
|
-
|
|
846
|
-
* Takes in a URL, and returns the corresponding URL that could be used to
|
|
847
|
-
* lookup the entry in the precache.
|
|
848
|
-
*
|
|
849
|
-
* If a relative URL is provided, the location of the service worker file will
|
|
850
|
-
* be used as the base.
|
|
851
|
-
*
|
|
852
|
-
* For precached entries without revision information, the cache key will be the
|
|
853
|
-
* same as the original URL.
|
|
854
|
-
*
|
|
855
|
-
* For precached entries with revision information, the cache key will be the
|
|
856
|
-
* original URL with the addition of a query parameter used for keeping track of
|
|
857
|
-
* the revision info.
|
|
858
|
-
*
|
|
859
|
-
* @param url The URL whose cache key to look up.
|
|
860
|
-
* @returns The cache key that corresponds to that URL.
|
|
861
|
-
*/ function getCacheKeyForURL(url) {
|
|
513
|
+
function getCacheKeyForURL(url) {
|
|
862
514
|
const precacheController = getOrCreatePrecacheController();
|
|
863
515
|
return precacheController.getCacheKeyForURL(url);
|
|
864
516
|
}
|
|
865
517
|
|
|
866
|
-
|
|
867
|
-
* Helper function that calls `PrecacheController#matchPrecache`
|
|
868
|
-
* on the default `PrecacheController` instance.
|
|
869
|
-
*
|
|
870
|
-
* If you are creating your own `PrecacheController`, then call
|
|
871
|
-
* `PrecacheController#matchPrecache` on that instance,
|
|
872
|
-
* instead of using this function.
|
|
873
|
-
*
|
|
874
|
-
* @param request The key (without revisioning parameters)
|
|
875
|
-
* to look up in the precache.
|
|
876
|
-
* @returns
|
|
877
|
-
*/ function matchPrecache(request) {
|
|
518
|
+
function matchPrecache(request) {
|
|
878
519
|
const precacheController = getOrCreatePrecacheController();
|
|
879
520
|
return precacheController.matchPrecache(request);
|
|
880
521
|
}
|
|
881
522
|
|
|
882
|
-
|
|
883
|
-
* Adds items to the precache list, removing any duplicates and
|
|
884
|
-
* stores the files in the precache cache when the service
|
|
885
|
-
* worker installs.
|
|
886
|
-
*
|
|
887
|
-
* This method can be called multiple times.
|
|
888
|
-
*
|
|
889
|
-
* Please note: This method **will not** serve any of the cached files for you.
|
|
890
|
-
* It only precaches files. To respond to a network request you call
|
|
891
|
-
* `@serwist/precaching.addRoute`.
|
|
892
|
-
*
|
|
893
|
-
* If you have a single array of files to precache, you can just call
|
|
894
|
-
* `@serwist/precaching.precacheAndRoute`.
|
|
895
|
-
*
|
|
896
|
-
* @param entries Array of entries to precache.
|
|
897
|
-
*/ function precache(entries) {
|
|
523
|
+
function precache(entries) {
|
|
898
524
|
const precacheController = getOrCreatePrecacheController();
|
|
899
525
|
precacheController.precache(entries);
|
|
900
526
|
}
|
|
901
527
|
|
|
902
|
-
|
|
903
|
-
* This method will add entries to the precache list and add a route to
|
|
904
|
-
* respond to fetch events.
|
|
905
|
-
*
|
|
906
|
-
* This is a convenience method that will call
|
|
907
|
-
* `@serwist/precaching.precache` and
|
|
908
|
-
* `@serwist/precaching.addRoute` in a single call.
|
|
909
|
-
*
|
|
910
|
-
* @param entries Array of entries to precache.
|
|
911
|
-
* @param options See the `@serwist/precaching.PrecacheRoute` options.
|
|
912
|
-
*/ function precacheAndRoute(entries, options) {
|
|
528
|
+
function precacheAndRoute(entries, options) {
|
|
913
529
|
precache(entries);
|
|
914
530
|
addRoute(options);
|
|
915
531
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serwist/precaching",
|
|
3
|
-
"version": "9.0.0-preview.
|
|
3
|
+
"version": "9.0.0-preview.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "This module efficiently precaches assets.",
|
|
6
6
|
"files": [
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
"./package.json": "./package.json"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@serwist/core": "9.0.0-preview.
|
|
32
|
-
"@serwist/routing": "9.0.0-preview.
|
|
33
|
-
"@serwist/strategies": "9.0.0-preview.
|
|
31
|
+
"@serwist/core": "9.0.0-preview.1",
|
|
32
|
+
"@serwist/routing": "9.0.0-preview.1",
|
|
33
|
+
"@serwist/strategies": "9.0.0-preview.1"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"rollup": "4.9.6",
|
|
37
37
|
"typescript": "5.4.0-dev.20240203",
|
|
38
|
-
"@serwist/constants": "9.0.0-preview.
|
|
38
|
+
"@serwist/constants": "9.0.0-preview.1"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
41
|
"typescript": ">=5.0.0"
|