@serwist/precaching 9.0.0-preview.0 → 9.0.0-preview.10

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.
@@ -15,6 +15,5 @@ import type { PrecacheEntry } from "./_types.js";
15
15
  *
16
16
  * @param entries Array of entries to precache.
17
17
  */
18
- declare function precache(entries: (PrecacheEntry | string)[]): void;
19
- export { precache };
18
+ export declare const precache: (entries: (PrecacheEntry | string)[]) => void;
20
19
  //# sourceMappingURL=precache.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"precache.d.ts","sourceRoot":"","sources":["../src/precache.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD;;;;;;;;;;;;;;;GAeG;AACH,iBAAS,QAAQ,CAAC,OAAO,EAAE,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,GAAG,IAAI,CAG3D;AAED,OAAO,EAAE,QAAQ,EAAE,CAAC"}
1
+ {"version":3,"file":"precache.d.ts","sourceRoot":"","sources":["../src/precache.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,QAAQ,YAAa,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,KAAG,IAG9D,CAAC"}
@@ -10,6 +10,5 @@ import type { PrecacheEntry, PrecacheRouteOptions } from "./_types.js";
10
10
  * @param entries Array of entries to precache.
11
11
  * @param options See the `@serwist/precaching.PrecacheRoute` options.
12
12
  */
13
- declare function precacheAndRoute(entries: (PrecacheEntry | string)[], options?: PrecacheRouteOptions): void;
14
- export { precacheAndRoute };
13
+ export declare const precacheAndRoute: (entries: (PrecacheEntry | string)[], options?: PrecacheRouteOptions) => void;
15
14
  //# sourceMappingURL=precacheAndRoute.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"precacheAndRoute.d.ts","sourceRoot":"","sources":["../src/precacheAndRoute.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAIvE;;;;;;;;;;GAUG;AACH,iBAAS,gBAAgB,CAAC,OAAO,EAAE,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAGnG;AAED,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"precacheAndRoute.d.ts","sourceRoot":"","sources":["../src/precacheAndRoute.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAIvE;;;;;;;;;;GAUG;AACH,eAAO,MAAM,gBAAgB,YAAa,CAAC,aAAa,GAAG,MAAM,CAAC,EAAE,YAAY,oBAAoB,KAAG,IAGtG,CAAC"}
@@ -14,6 +14,5 @@
14
14
  * @returns A list of all the cache names that were deleted.
15
15
  * @private
16
16
  */
17
- declare const deleteOutdatedCaches: (currentPrecacheName: string, substringToFind?: string) => Promise<string[]>;
18
- export { deleteOutdatedCaches };
17
+ export declare const deleteOutdatedCaches: (currentPrecacheName: string, substringToFind?: string) => Promise<string[]>;
19
18
  //# sourceMappingURL=deleteOutdatedCaches.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"deleteOutdatedCaches.d.ts","sourceRoot":"","sources":["../../src/utils/deleteOutdatedCaches.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;GAeG;AACH,QAAA,MAAM,oBAAoB,wBAA+B,MAAM,oBAAmB,MAAM,KAAuB,QAAQ,MAAM,EAAE,CAU9H,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,CAAC"}
1
+ {"version":3,"file":"deleteOutdatedCaches.d.ts","sourceRoot":"","sources":["../../src/utils/deleteOutdatedCaches.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,oBAAoB,wBAA+B,MAAM,oBAAmB,MAAM,KAAuB,QAAQ,MAAM,EAAE,CAUrI,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@serwist/precaching",
3
- "version": "9.0.0-preview.0",
3
+ "version": "9.0.0-preview.10",
4
4
  "type": "module",
5
5
  "description": "This module efficiently precaches assets.",
6
6
  "files": [
@@ -28,14 +28,15 @@
28
28
  "./package.json": "./package.json"
29
29
  },
30
30
  "dependencies": {
31
- "@serwist/core": "9.0.0-preview.0",
32
- "@serwist/routing": "9.0.0-preview.0",
33
- "@serwist/strategies": "9.0.0-preview.0"
31
+ "@serwist/core": "9.0.0-preview.10",
32
+ "@serwist/routing": "9.0.0-preview.10",
33
+ "@serwist/strategies": "9.0.0-preview.10"
34
34
  },
35
35
  "devDependencies": {
36
36
  "rollup": "4.9.6",
37
- "typescript": "5.4.0-dev.20240203",
38
- "@serwist/constants": "9.0.0-preview.0"
37
+ "typescript": "5.4.0-dev.20240206",
38
+ "@serwist/constants": "9.0.0-preview.10",
39
+ "@serwist/utils": "9.0.0-preview.10"
39
40
  },
40
41
  "peerDependencies": {
41
42
  "typescript": ">=5.0.0"
@@ -9,6 +9,7 @@
9
9
  import type { RouteHandlerCallback, SerwistPlugin } from "@serwist/core";
10
10
  import { assert, SerwistError, logger, privateCacheNames, waitUntil } from "@serwist/core/internal";
11
11
  import type { Strategy } from "@serwist/strategies";
12
+ import { parallel } from "@serwist/utils";
12
13
 
13
14
  import { PrecacheStrategy } from "./PrecacheStrategy.js";
14
15
  import type { CleanupResult, InstallResult, PrecacheEntry } from "./_types.js";
@@ -19,7 +20,7 @@ import { printCleanupDetails } from "./utils/printCleanupDetails.js";
19
20
  import { printInstallDetails } from "./utils/printInstallDetails.js";
20
21
 
21
22
  // Give TypeScript the correct global.
22
- declare let self: ServiceWorkerGlobalScope;
23
+ declare const self: ServiceWorkerGlobalScope;
23
24
 
24
25
  interface PrecacheControllerOptions {
25
26
  /**
@@ -36,13 +37,21 @@ interface PrecacheControllerOptions {
36
37
  * a precache miss.
37
38
  */
38
39
  fallbackToNetwork?: boolean;
40
+ /**
41
+ * A number of how many precache requests should be made concurrently.
42
+ * By default, this value is set to 1, but this can be overriden by
43
+ * setting this option or `self.__WB_CONCURRENT_PRECACHING`. The former takes
44
+ * precedence over the latter.
45
+ */
46
+ concurrentPrecaching?: number;
39
47
  }
40
48
 
41
49
  /**
42
50
  * Performs efficient precaching of assets.
43
51
  */
44
- class PrecacheController {
52
+ export class PrecacheController {
45
53
  private _installAndActiveListenersAdded?: boolean;
54
+ private _concurrentPrecaching: number | undefined;
46
55
  private readonly _strategy: Strategy;
47
56
  private readonly _urlsToCacheKeys: Map<string, string> = new Map();
48
57
  private readonly _urlsToCacheModes: Map<string, "reload" | "default" | "no-store" | "no-cache" | "force-cache" | "only-if-cached"> = new Map();
@@ -53,12 +62,13 @@ class PrecacheController {
53
62
  *
54
63
  * @param options
55
64
  */
56
- constructor({ cacheName, plugins = [], fallbackToNetwork = true }: PrecacheControllerOptions = {}) {
65
+ constructor({ cacheName, plugins = [], fallbackToNetwork = true, concurrentPrecaching }: PrecacheControllerOptions = {}) {
57
66
  this._strategy = new PrecacheStrategy({
58
67
  cacheName: privateCacheNames.getPrecacheName(cacheName),
59
68
  plugins: [...plugins, new PrecacheCacheKeyPlugin({ precacheController: this })],
60
69
  fallbackToNetwork,
61
70
  });
71
+ this._concurrentPrecaching = concurrentPrecaching;
62
72
 
63
73
  // Bind the install and activate methods to the instance.
64
74
  this.install = this.install.bind(this);
@@ -165,15 +175,20 @@ class PrecacheController {
165
175
  * @returns
166
176
  */
167
177
  install(event: ExtendableEvent): Promise<InstallResult> {
168
- // waitUntil returns Promise<any>
169
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
170
- return waitUntil(event, async () => {
178
+ return waitUntil<InstallResult>(event, async () => {
171
179
  const installReportPlugin = new PrecacheInstallReportPlugin();
172
180
  this.strategy.plugins.push(installReportPlugin);
173
181
 
174
- // Cache entries one at a time.
175
- // See https://github.com/GoogleChrome/workbox/issues/2528
176
- for (const [url, cacheKey] of this._urlsToCacheKeys) {
182
+ let concurrents = this._concurrentPrecaching;
183
+
184
+ if (concurrents === undefined) {
185
+ if (!("__WB_CONCURRENT_PRECACHING" in globalThis)) {
186
+ self.__WB_CONCURRENT_PRECACHING = 1;
187
+ }
188
+ concurrents = self.__WB_CONCURRENT_PRECACHING;
189
+ }
190
+
191
+ await parallel(concurrents, Array.from(this._urlsToCacheKeys.entries()), async ([url, cacheKey]) => {
177
192
  const integrity = this._cacheKeysToIntegrities.get(cacheKey);
178
193
  const cacheMode = this._urlsToCacheModes.get(url);
179
194
 
@@ -190,7 +205,7 @@ class PrecacheController {
190
205
  event,
191
206
  }),
192
207
  );
193
- }
208
+ });
194
209
 
195
210
  const { updatedURLs, notUpdatedURLs } = installReportPlugin;
196
211
 
@@ -213,26 +228,25 @@ class PrecacheController {
213
228
  * @returns
214
229
  */
215
230
  activate(event: ExtendableEvent): Promise<CleanupResult> {
216
- // waitUntil returns Promise<any>
217
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
218
- return waitUntil(event, async () => {
231
+ return waitUntil<CleanupResult>(event, async () => {
219
232
  const cache = await self.caches.open(this.strategy.cacheName);
220
233
  const currentlyCachedRequests = await cache.keys();
221
234
  const expectedCacheKeys = new Set(this._urlsToCacheKeys.values());
222
235
 
223
- const deletedURLs = [];
236
+ const deletedCacheRequests: string[] = [];
237
+
224
238
  for (const request of currentlyCachedRequests) {
225
239
  if (!expectedCacheKeys.has(request.url)) {
226
240
  await cache.delete(request);
227
- deletedURLs.push(request.url);
241
+ deletedCacheRequests.push(request.url);
228
242
  }
229
243
  }
230
244
 
231
245
  if (process.env.NODE_ENV !== "production") {
232
- printCleanupDetails(deletedURLs);
246
+ printCleanupDetails(deletedCacheRequests);
233
247
  }
234
248
 
235
- return { deletedURLs };
249
+ return { deletedCacheRequests };
236
250
  });
237
251
  }
238
252
 
@@ -327,5 +341,3 @@ class PrecacheController {
327
341
  };
328
342
  }
329
343
  }
330
-
331
- export { PrecacheController };
@@ -6,28 +6,39 @@
6
6
  https://opensource.org/licenses/MIT.
7
7
  */
8
8
 
9
- import type { SerwistPlugin } from "@serwist/core";
9
+ import type { HandlerDidErrorCallbackParam, SerwistPlugin } from "@serwist/core";
10
10
 
11
11
  import type { PrecacheController } from "./PrecacheController.js";
12
12
  import { getOrCreatePrecacheController } from "./utils/getOrCreatePrecacheController.js";
13
13
 
14
- interface PrecacheFallbackPluginOptions {
14
+ export interface PrecacheFallbackEntry {
15
15
  /**
16
- * A precached URL to use as the fallback
16
+ * A function that checks whether the fallback entry can be used
17
+ * for a request.
18
+ */
19
+ matcher: (param: HandlerDidErrorCallbackParam) => boolean;
20
+ /**
21
+ * A precached URL to be used as a fallback.
22
+ */
23
+ url: string;
24
+ }
25
+
26
+ export interface PrecacheFallbackPluginOptions {
27
+ /**
28
+ * Precached URLs to use as the fallback
17
29
  * if the associated strategy can't generate a response.
18
30
  */
19
- fallbackURL: string;
31
+ fallbackUrls: (string | PrecacheFallbackEntry)[];
20
32
  /**
21
- * An optional
22
- * PrecacheController instance. If not provided, the default
23
- * PrecacheController will be used.
33
+ * An optional `PrecacheController` instance. If not provided, the default
34
+ * `PrecacheController` will be used.
24
35
  */
25
36
  precacheController?: PrecacheController;
26
37
  }
27
38
 
28
39
  /**
29
- * `PrecacheFallbackPlugin` allows you to specify an "offline fallback"
30
- * response to be used when a given strategy is unable to generate a response.
40
+ * `PrecacheFallbackPlugin` allows you to specify offline fallbacks
41
+ * to be used when a given strategy is unable to generate a response.
31
42
  *
32
43
  * It does this by intercepting the `handlerDidError` plugin callback
33
44
  * and returning a precached response, taking the expected revision parameter
@@ -37,25 +48,39 @@ interface PrecacheFallbackPluginOptions {
37
48
  * constructor, the default instance will be used. Generally speaking, most
38
49
  * developers will end up using the default.
39
50
  */
40
- class PrecacheFallbackPlugin implements SerwistPlugin {
41
- private readonly _fallbackURL: string;
51
+ export class PrecacheFallbackPlugin implements SerwistPlugin {
52
+ private readonly _fallbackUrls: (string | PrecacheFallbackEntry)[];
42
53
  private readonly _precacheController: PrecacheController;
43
54
 
44
55
  /**
45
- * Constructs a new PrecacheFallbackPlugin with the associated fallbackURL.
56
+ * Constructs a new `PrecacheFallbackPlugin` with the associated `fallbackUrls`.
46
57
  *
47
58
  * @param config
48
59
  */
49
- constructor({ fallbackURL, precacheController }: PrecacheFallbackPluginOptions) {
50
- this._fallbackURL = fallbackURL;
60
+ constructor({ fallbackUrls, precacheController }: PrecacheFallbackPluginOptions) {
61
+ this._fallbackUrls = fallbackUrls;
51
62
  this._precacheController = precacheController || getOrCreatePrecacheController();
52
63
  }
53
64
 
54
65
  /**
55
- * @returns The precache response for the fallback URL.
66
+ * @returns The precache response for one of the fallback URLs, or `undefined` if
67
+ * nothing satisfies the conditions.
56
68
  * @private
57
69
  */
58
- handlerDidError: SerwistPlugin["handlerDidError"] = () => this._precacheController.matchPrecache(this._fallbackURL);
70
+ async handlerDidError(param: HandlerDidErrorCallbackParam) {
71
+ for (const fallback of this._fallbackUrls) {
72
+ if (typeof fallback === "string") {
73
+ const fallbackResponse = await this._precacheController.matchPrecache(fallback);
74
+ if (fallbackResponse !== undefined) {
75
+ return fallbackResponse;
76
+ }
77
+ } else if (fallback.matcher(param)) {
78
+ const fallbackResponse = await this._precacheController.matchPrecache(fallback.url);
79
+ if (fallbackResponse !== undefined) {
80
+ return fallbackResponse;
81
+ }
82
+ }
83
+ }
84
+ return undefined;
85
+ }
59
86
  }
60
-
61
- export { PrecacheFallbackPlugin };
package/src/addRoute.ts CHANGED
@@ -23,11 +23,9 @@ import { getOrCreatePrecacheController } from "./utils/getOrCreatePrecacheContro
23
23
  *
24
24
  * @param options See the `@serwist/precaching.PrecacheRoute` options.
25
25
  */
26
- function addRoute(options?: PrecacheRouteOptions): void {
26
+ export const addRoute = (options?: PrecacheRouteOptions): void => {
27
27
  const precacheController = getOrCreatePrecacheController();
28
28
 
29
29
  const precacheRoute = new PrecacheRoute(precacheController, options);
30
30
  registerRoute(precacheRoute);
31
- }
32
-
33
- export { addRoute };
31
+ };
@@ -10,25 +10,24 @@ import { logger, privateCacheNames } from "@serwist/core/internal";
10
10
 
11
11
  import { deleteOutdatedCaches } from "./utils/deleteOutdatedCaches.js";
12
12
 
13
+ declare const self: ServiceWorkerGlobalScope;
14
+
13
15
  /**
14
16
  * Adds an `activate` event listener which will clean up incompatible
15
17
  * precaches that were created by older versions of Serwist.
16
18
  */
17
- function cleanupOutdatedCaches(): void {
18
- // See https://github.com/Microsoft/TypeScript/issues/28357#issuecomment-436484705
19
- self.addEventListener("activate", ((event: ExtendableEvent) => {
19
+ export const cleanupOutdatedCaches = (): void => {
20
+ self.addEventListener("activate", (event: ExtendableEvent) => {
20
21
  const cacheName = privateCacheNames.getPrecacheName();
21
22
 
22
23
  event.waitUntil(
23
24
  deleteOutdatedCaches(cacheName).then((cachesDeleted) => {
24
25
  if (process.env.NODE_ENV !== "production") {
25
26
  if (cachesDeleted.length > 0) {
26
- logger.log("The following out-of-date precaches were cleaned up " + "automatically:", cachesDeleted);
27
+ logger.log("The following out-of-date precaches were cleaned up automatically:", cachesDeleted);
27
28
  }
28
29
  }
29
30
  }),
30
31
  );
31
- }) as EventListener);
32
- }
33
-
34
- export { cleanupOutdatedCaches };
32
+ });
33
+ };
@@ -24,9 +24,7 @@ import { getOrCreatePrecacheController } from "./utils/getOrCreatePrecacheContro
24
24
  * response from the network if there's a precache miss.
25
25
  * @return
26
26
  */
27
- function createHandlerBoundToURL(url: string): RouteHandlerCallback {
27
+ export const createHandlerBoundToURL = (url: string): RouteHandlerCallback => {
28
28
  const precacheController = getOrCreatePrecacheController();
29
29
  return precacheController.createHandlerBoundToURL(url);
30
- }
31
-
32
- export { createHandlerBoundToURL };
30
+ };
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@
8
8
 
9
9
  import { PrecacheController } from "./PrecacheController.js";
10
10
  import { PrecacheFallbackPlugin } from "./PrecacheFallbackPlugin.js";
11
+ import type { PrecacheFallbackEntry, PrecacheFallbackPluginOptions } from "./PrecacheFallbackPlugin.js";
11
12
  import { PrecacheRoute } from "./PrecacheRoute.js";
12
13
  import { PrecacheStrategy } from "./PrecacheStrategy.js";
13
14
  import { addPlugins } from "./addPlugins.js";
@@ -45,4 +46,6 @@ export {
45
46
  PrecacheStrategy,
46
47
  };
47
48
 
48
- export * from "./_types.js";
49
+ export type * from "./_types.js";
50
+
51
+ export type { PrecacheFallbackPluginOptions, PrecacheFallbackEntry };
package/src/precache.ts CHANGED
@@ -25,9 +25,7 @@ import { getOrCreatePrecacheController } from "./utils/getOrCreatePrecacheContro
25
25
  *
26
26
  * @param entries Array of entries to precache.
27
27
  */
28
- function precache(entries: (PrecacheEntry | string)[]): void {
28
+ export const precache = (entries: (PrecacheEntry | string)[]): void => {
29
29
  const precacheController = getOrCreatePrecacheController();
30
30
  precacheController.precache(entries);
31
- }
32
-
33
- export { precache };
31
+ };
@@ -21,9 +21,7 @@ import { precache } from "./precache.js";
21
21
  * @param entries Array of entries to precache.
22
22
  * @param options See the `@serwist/precaching.PrecacheRoute` options.
23
23
  */
24
- function precacheAndRoute(entries: (PrecacheEntry | string)[], options?: PrecacheRouteOptions): void {
24
+ export const precacheAndRoute = (entries: (PrecacheEntry | string)[], options?: PrecacheRouteOptions): void => {
25
25
  precache(entries);
26
26
  addRoute(options);
27
- }
28
-
29
- export { precacheAndRoute };
27
+ };
@@ -27,7 +27,7 @@ const SUBSTRING_TO_FIND = "-precache-";
27
27
  * @returns A list of all the cache names that were deleted.
28
28
  * @private
29
29
  */
30
- const deleteOutdatedCaches = async (currentPrecacheName: string, substringToFind: string = SUBSTRING_TO_FIND): Promise<string[]> => {
30
+ export const deleteOutdatedCaches = async (currentPrecacheName: string, substringToFind: string = SUBSTRING_TO_FIND): Promise<string[]> => {
31
31
  const cacheNames = await self.caches.keys();
32
32
 
33
33
  const cacheNamesToDelete = cacheNames.filter((cacheName) => {
@@ -38,5 +38,3 @@ const deleteOutdatedCaches = async (currentPrecacheName: string, substringToFind
38
38
 
39
39
  return cacheNamesToDelete;
40
40
  };
41
-
42
- export { deleteOutdatedCaches };