UNPKG

35.4 kBJavaScriptView Raw
1this.workbox = this.workbox || {};
2this.workbox.strategies = (function (exports, logger_mjs, assert_mjs, cacheNames_mjs, cacheWrapper_mjs, fetchWrapper_mjs, getFriendlyURL_mjs, WorkboxError_mjs) {
3 'use strict';
4
5 try {
6 self['workbox:strategies:4.1.1'] && _();
7 } catch (e) {} // eslint-disable-line
8
9 /*
10 Copyright 2018 Google LLC
11
12 Use of this source code is governed by an MIT-style
13 license that can be found in the LICENSE file or at
14 https://opensource.org/licenses/MIT.
15 */
16
17 const getFriendlyURL = url => {
18 const urlObj = new URL(url, location);
19
20 if (urlObj.origin === location.origin) {
21 return urlObj.pathname;
22 }
23
24 return urlObj.href;
25 };
26
27 const messages = {
28 strategyStart: (strategyName, request) => `Using ${strategyName} to ` + `respond to '${getFriendlyURL(request.url)}'`,
29 printFinalResponse: response => {
30 if (response) {
31 logger_mjs.logger.groupCollapsed(`View the final response here.`);
32 logger_mjs.logger.log(response);
33 logger_mjs.logger.groupEnd();
34 }
35 }
36 };
37
38 /*
39 Copyright 2018 Google LLC
40
41 Use of this source code is governed by an MIT-style
42 license that can be found in the LICENSE file or at
43 https://opensource.org/licenses/MIT.
44 */
45 /**
46 * An implementation of a [cache-first]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-falling-back-to-network}
47 * request strategy.
48 *
49 * A cache first strategy is useful for assets that have been revisioned,
50 * such as URLs like `/styles/example.a8f5f1.css`, since they
51 * can be cached for long periods of time.
52 *
53 * If the network request fails, and there is no cache match, this will throw
54 * a `WorkboxError` exception.
55 *
56 * @memberof workbox.strategies
57 */
58
59 class CacheFirst {
60 /**
61 * @param {Object} options
62 * @param {string} options.cacheName Cache name to store and retrieve
63 * requests. Defaults to cache names provided by
64 * [workbox-core]{@link workbox.core.cacheNames}.
65 * @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
66 * to use in conjunction with this caching strategy.
67 * @param {Object} options.fetchOptions Values passed along to the
68 * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
69 * of all fetch() requests made by this strategy.
70 * @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
71 */
72 constructor(options = {}) {
73 this._cacheName = cacheNames_mjs.cacheNames.getRuntimeName(options.cacheName);
74 this._plugins = options.plugins || [];
75 this._fetchOptions = options.fetchOptions || null;
76 this._matchOptions = options.matchOptions || null;
77 }
78 /**
79 * This method will perform a request strategy and follows an API that
80 * will work with the
81 * [Workbox Router]{@link workbox.routing.Router}.
82 *
83 * @param {Object} options
84 * @param {Request} options.request The request to run this strategy for.
85 * @param {Event} [options.event] The event that triggered the request.
86 * @return {Promise<Response>}
87 */
88
89
90 async handle({
91 event,
92 request
93 }) {
94 return this.makeRequest({
95 event,
96 request: request || event.request
97 });
98 }
99 /**
100 * This method can be used to perform a make a standalone request outside the
101 * context of the [Workbox Router]{@link workbox.routing.Router}.
102 *
103 * See "[Advanced Recipes](https://developers.google.com/web/tools/workbox/guides/advanced-recipes#make-requests)"
104 * for more usage information.
105 *
106 * @param {Object} options
107 * @param {Request|string} options.request Either a
108 * [`Request`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Request}
109 * object, or a string URL, corresponding to the request to be made.
110 * @param {FetchEvent} [options.event] If provided, `event.waitUntil()` will
111 be called automatically to extend the service worker's lifetime.
112 * @return {Promise<Response>}
113 */
114
115
116 async makeRequest({
117 event,
118 request
119 }) {
120 const logs = [];
121
122 if (typeof request === 'string') {
123 request = new Request(request);
124 }
125
126 {
127 assert_mjs.assert.isInstance(request, Request, {
128 moduleName: 'workbox-strategies',
129 className: 'CacheFirst',
130 funcName: 'makeRequest',
131 paramName: 'request'
132 });
133 }
134
135 let response = await cacheWrapper_mjs.cacheWrapper.match({
136 cacheName: this._cacheName,
137 request,
138 event,
139 matchOptions: this._matchOptions,
140 plugins: this._plugins
141 });
142 let error;
143
144 if (!response) {
145 {
146 logs.push(`No response found in the '${this._cacheName}' cache. ` + `Will respond with a network request.`);
147 }
148
149 try {
150 response = await this._getFromNetwork(request, event);
151 } catch (err) {
152 error = err;
153 }
154
155 {
156 if (response) {
157 logs.push(`Got response from network.`);
158 } else {
159 logs.push(`Unable to get a response from the network.`);
160 }
161 }
162 } else {
163 {
164 logs.push(`Found a cached response in the '${this._cacheName}' cache.`);
165 }
166 }
167
168 {
169 logger_mjs.logger.groupCollapsed(messages.strategyStart('CacheFirst', request));
170
171 for (let log of logs) {
172 logger_mjs.logger.log(log);
173 }
174
175 messages.printFinalResponse(response);
176 logger_mjs.logger.groupEnd();
177 }
178
179 if (!response) {
180 throw new WorkboxError_mjs.WorkboxError('no-response', {
181 url: request.url,
182 error
183 });
184 }
185
186 return response;
187 }
188 /**
189 * Handles the network and cache part of CacheFirst.
190 *
191 * @param {Request} request
192 * @param {FetchEvent} [event]
193 * @return {Promise<Response>}
194 *
195 * @private
196 */
197
198
199 async _getFromNetwork(request, event) {
200 const response = await fetchWrapper_mjs.fetchWrapper.fetch({
201 request,
202 event,
203 fetchOptions: this._fetchOptions,
204 plugins: this._plugins
205 }); // Keep the service worker while we put the request to the cache
206
207 const responseClone = response.clone();
208 const cachePutPromise = cacheWrapper_mjs.cacheWrapper.put({
209 cacheName: this._cacheName,
210 request,
211 response: responseClone,
212 event,
213 plugins: this._plugins
214 });
215
216 if (event) {
217 try {
218 event.waitUntil(cachePutPromise);
219 } catch (error) {
220 {
221 logger_mjs.logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache for '${getFriendlyURL_mjs.getFriendlyURL(request.url)}'.`);
222 }
223 }
224 }
225
226 return response;
227 }
228
229 }
230
231 /*
232 Copyright 2018 Google LLC
233
234 Use of this source code is governed by an MIT-style
235 license that can be found in the LICENSE file or at
236 https://opensource.org/licenses/MIT.
237 */
238 /**
239 * An implementation of a
240 * [cache-only]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#cache-only}
241 * request strategy.
242 *
243 * This class is useful if you want to take advantage of any
244 * [Workbox plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}.
245 *
246 * If there is no cache match, this will throw a `WorkboxError` exception.
247 *
248 * @memberof workbox.strategies
249 */
250
251 class CacheOnly {
252 /**
253 * @param {Object} options
254 * @param {string} options.cacheName Cache name to store and retrieve
255 * requests. Defaults to cache names provided by
256 * [workbox-core]{@link workbox.core.cacheNames}.
257 * @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
258 * to use in conjunction with this caching strategy.
259 * @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
260 */
261 constructor(options = {}) {
262 this._cacheName = cacheNames_mjs.cacheNames.getRuntimeName(options.cacheName);
263 this._plugins = options.plugins || [];
264 this._matchOptions = options.matchOptions || null;
265 }
266 /**
267 * This method will perform a request strategy and follows an API that
268 * will work with the
269 * [Workbox Router]{@link workbox.routing.Router}.
270 *
271 * @param {Object} options
272 * @param {Request} options.request The request to run this strategy for.
273 * @param {Event} [options.event] The event that triggered the request.
274 * @return {Promise<Response>}
275 */
276
277
278 async handle({
279 event,
280 request
281 }) {
282 return this.makeRequest({
283 event,
284 request: request || event.request
285 });
286 }
287 /**
288 * This method can be used to perform a make a standalone request outside the
289 * context of the [Workbox Router]{@link workbox.routing.Router}.
290 *
291 * See "[Advanced Recipes](https://developers.google.com/web/tools/workbox/guides/advanced-recipes#make-requests)"
292 * for more usage information.
293 *
294 * @param {Object} options
295 * @param {Request|string} options.request Either a
296 * [`Request`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Request}
297 * object, or a string URL, corresponding to the request to be made.
298 * @param {FetchEvent} [options.event] If provided, `event.waitUntil()` will
299 * be called automatically to extend the service worker's lifetime.
300 * @return {Promise<Response>}
301 */
302
303
304 async makeRequest({
305 event,
306 request
307 }) {
308 if (typeof request === 'string') {
309 request = new Request(request);
310 }
311
312 {
313 assert_mjs.assert.isInstance(request, Request, {
314 moduleName: 'workbox-strategies',
315 className: 'CacheOnly',
316 funcName: 'makeRequest',
317 paramName: 'request'
318 });
319 }
320
321 const response = await cacheWrapper_mjs.cacheWrapper.match({
322 cacheName: this._cacheName,
323 request,
324 event,
325 matchOptions: this._matchOptions,
326 plugins: this._plugins
327 });
328
329 {
330 logger_mjs.logger.groupCollapsed(messages.strategyStart('CacheOnly', request));
331
332 if (response) {
333 logger_mjs.logger.log(`Found a cached response in the '${this._cacheName}'` + ` cache.`);
334 messages.printFinalResponse(response);
335 } else {
336 logger_mjs.logger.log(`No response found in the '${this._cacheName}' cache.`);
337 }
338
339 logger_mjs.logger.groupEnd();
340 }
341
342 if (!response) {
343 throw new WorkboxError_mjs.WorkboxError('no-response', {
344 url: request.url
345 });
346 }
347
348 return response;
349 }
350
351 }
352
353 /*
354 Copyright 2018 Google LLC
355
356 Use of this source code is governed by an MIT-style
357 license that can be found in the LICENSE file or at
358 https://opensource.org/licenses/MIT.
359 */
360 const cacheOkAndOpaquePlugin = {
361 /**
362 * Returns a valid response (to allow caching) if the status is 200 (OK) or
363 * 0 (opaque).
364 *
365 * @param {Object} options
366 * @param {Response} options.response
367 * @return {Response|null}
368 *
369 * @private
370 */
371 cacheWillUpdate: ({
372 response
373 }) => {
374 if (response.status === 200 || response.status === 0) {
375 return response;
376 }
377
378 return null;
379 }
380 };
381
382 /*
383 Copyright 2018 Google LLC
384
385 Use of this source code is governed by an MIT-style
386 license that can be found in the LICENSE file or at
387 https://opensource.org/licenses/MIT.
388 */
389 /**
390 * An implementation of a
391 * [network first]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#network-falling-back-to-cache}
392 * request strategy.
393 *
394 * By default, this strategy will cache responses with a 200 status code as
395 * well as [opaque responses]{@link https://developers.google.com/web/tools/workbox/guides/handle-third-party-requests}.
396 * Opaque responses are are cross-origin requests where the response doesn't
397 * support [CORS]{@link https://enable-cors.org/}.
398 *
399 * If the network request fails, and there is no cache match, this will throw
400 * a `WorkboxError` exception.
401 *
402 * @memberof workbox.strategies
403 */
404
405 class NetworkFirst {
406 /**
407 * @param {Object} options
408 * @param {string} options.cacheName Cache name to store and retrieve
409 * requests. Defaults to cache names provided by
410 * [workbox-core]{@link workbox.core.cacheNames}.
411 * @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
412 * to use in conjunction with this caching strategy.
413 * @param {Object} options.fetchOptions Values passed along to the
414 * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
415 * of all fetch() requests made by this strategy.
416 * @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
417 * @param {number} options.networkTimeoutSeconds If set, any network requests
418 * that fail to respond within the timeout will fallback to the cache.
419 *
420 * This option can be used to combat
421 * "[lie-fi]{@link https://developers.google.com/web/fundamentals/performance/poor-connectivity/#lie-fi}"
422 * scenarios.
423 */
424 constructor(options = {}) {
425 this._cacheName = cacheNames_mjs.cacheNames.getRuntimeName(options.cacheName);
426
427 if (options.plugins) {
428 let isUsingCacheWillUpdate = options.plugins.some(plugin => !!plugin.cacheWillUpdate);
429 this._plugins = isUsingCacheWillUpdate ? options.plugins : [cacheOkAndOpaquePlugin, ...options.plugins];
430 } else {
431 // No plugins passed in, use the default plugin.
432 this._plugins = [cacheOkAndOpaquePlugin];
433 }
434
435 this._networkTimeoutSeconds = options.networkTimeoutSeconds;
436
437 {
438 if (this._networkTimeoutSeconds) {
439 assert_mjs.assert.isType(this._networkTimeoutSeconds, 'number', {
440 moduleName: 'workbox-strategies',
441 className: 'NetworkFirst',
442 funcName: 'constructor',
443 paramName: 'networkTimeoutSeconds'
444 });
445 }
446 }
447
448 this._fetchOptions = options.fetchOptions || null;
449 this._matchOptions = options.matchOptions || null;
450 }
451 /**
452 * This method will perform a request strategy and follows an API that
453 * will work with the
454 * [Workbox Router]{@link workbox.routing.Router}.
455 *
456 * @param {Object} options
457 * @param {Request} options.request The request to run this strategy for.
458 * @param {Event} [options.event] The event that triggered the request.
459 * @return {Promise<Response>}
460 */
461
462
463 async handle({
464 event,
465 request
466 }) {
467 return this.makeRequest({
468 event,
469 request: request || event.request
470 });
471 }
472 /**
473 * This method can be used to perform a make a standalone request outside the
474 * context of the [Workbox Router]{@link workbox.routing.Router}.
475 *
476 * See "[Advanced Recipes](https://developers.google.com/web/tools/workbox/guides/advanced-recipes#make-requests)"
477 * for more usage information.
478 *
479 * @param {Object} options
480 * @param {Request|string} options.request Either a
481 * [`Request`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Request}
482 * object, or a string URL, corresponding to the request to be made.
483 * @param {FetchEvent} [options.event] If provided, `event.waitUntil()` will
484 * be called automatically to extend the service worker's lifetime.
485 * @return {Promise<Response>}
486 */
487
488
489 async makeRequest({
490 event,
491 request
492 }) {
493 const logs = [];
494
495 if (typeof request === 'string') {
496 request = new Request(request);
497 }
498
499 {
500 assert_mjs.assert.isInstance(request, Request, {
501 moduleName: 'workbox-strategies',
502 className: 'NetworkFirst',
503 funcName: 'handle',
504 paramName: 'makeRequest'
505 });
506 }
507
508 const promises = [];
509 let timeoutId;
510
511 if (this._networkTimeoutSeconds) {
512 const {
513 id,
514 promise
515 } = this._getTimeoutPromise({
516 request,
517 event,
518 logs
519 });
520
521 timeoutId = id;
522 promises.push(promise);
523 }
524
525 const networkPromise = this._getNetworkPromise({
526 timeoutId,
527 request,
528 event,
529 logs
530 });
531
532 promises.push(networkPromise); // Promise.race() will resolve as soon as the first promise resolves.
533
534 let response = await Promise.race(promises); // If Promise.race() resolved with null, it might be due to a network
535 // timeout + a cache miss. If that were to happen, we'd rather wait until
536 // the networkPromise resolves instead of returning null.
537 // Note that it's fine to await an already-resolved promise, so we don't
538 // have to check to see if it's still "in flight".
539
540 if (!response) {
541 response = await networkPromise;
542 }
543
544 {
545 logger_mjs.logger.groupCollapsed(messages.strategyStart('NetworkFirst', request));
546
547 for (let log of logs) {
548 logger_mjs.logger.log(log);
549 }
550
551 messages.printFinalResponse(response);
552 logger_mjs.logger.groupEnd();
553 }
554
555 if (!response) {
556 throw new WorkboxError_mjs.WorkboxError('no-response', {
557 url: request.url
558 });
559 }
560
561 return response;
562 }
563 /**
564 * @param {Object} options
565 * @param {Request} options.request
566 * @param {Array} options.logs A reference to the logs array
567 * @param {Event} [options.event]
568 * @return {Promise<Response>}
569 *
570 * @private
571 */
572
573
574 _getTimeoutPromise({
575 request,
576 logs,
577 event
578 }) {
579 let timeoutId;
580 const timeoutPromise = new Promise(resolve => {
581 const onNetworkTimeout = async () => {
582 {
583 logs.push(`Timing out the network response at ` + `${this._networkTimeoutSeconds} seconds.`);
584 }
585
586 resolve((await this._respondFromCache({
587 request,
588 event
589 })));
590 };
591
592 timeoutId = setTimeout(onNetworkTimeout, this._networkTimeoutSeconds * 1000);
593 });
594 return {
595 promise: timeoutPromise,
596 id: timeoutId
597 };
598 }
599 /**
600 * @param {Object} options
601 * @param {number|undefined} options.timeoutId
602 * @param {Request} options.request
603 * @param {Array} options.logs A reference to the logs Array.
604 * @param {Event} [options.event]
605 * @return {Promise<Response>}
606 *
607 * @private
608 */
609
610
611 async _getNetworkPromise({
612 timeoutId,
613 request,
614 logs,
615 event
616 }) {
617 let error;
618 let response;
619
620 try {
621 response = await fetchWrapper_mjs.fetchWrapper.fetch({
622 request,
623 event,
624 fetchOptions: this._fetchOptions,
625 plugins: this._plugins
626 });
627 } catch (err) {
628 error = err;
629 }
630
631 if (timeoutId) {
632 clearTimeout(timeoutId);
633 }
634
635 {
636 if (response) {
637 logs.push(`Got response from network.`);
638 } else {
639 logs.push(`Unable to get a response from the network. Will respond ` + `with a cached response.`);
640 }
641 }
642
643 if (error || !response) {
644 response = await this._respondFromCache({
645 request,
646 event
647 });
648
649 {
650 if (response) {
651 logs.push(`Found a cached response in the '${this._cacheName}'` + ` cache.`);
652 } else {
653 logs.push(`No response found in the '${this._cacheName}' cache.`);
654 }
655 }
656 } else {
657 // Keep the service worker alive while we put the request in the cache
658 const responseClone = response.clone();
659 const cachePut = cacheWrapper_mjs.cacheWrapper.put({
660 cacheName: this._cacheName,
661 request,
662 response: responseClone,
663 event,
664 plugins: this._plugins
665 });
666
667 if (event) {
668 try {
669 // The event has been responded to so we can keep the SW alive to
670 // respond to the request
671 event.waitUntil(cachePut);
672 } catch (err) {
673 {
674 logger_mjs.logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache for '${getFriendlyURL_mjs.getFriendlyURL(request.url)}'.`);
675 }
676 }
677 }
678 }
679
680 return response;
681 }
682 /**
683 * Used if the network timeouts or fails to make the request.
684 *
685 * @param {Object} options
686 * @param {Request} request The request to match in the cache
687 * @param {Event} [options.event]
688 * @return {Promise<Object>}
689 *
690 * @private
691 */
692
693
694 _respondFromCache({
695 event,
696 request
697 }) {
698 return cacheWrapper_mjs.cacheWrapper.match({
699 cacheName: this._cacheName,
700 request,
701 event,
702 matchOptions: this._matchOptions,
703 plugins: this._plugins
704 });
705 }
706
707 }
708
709 /*
710 Copyright 2018 Google LLC
711
712 Use of this source code is governed by an MIT-style
713 license that can be found in the LICENSE file or at
714 https://opensource.org/licenses/MIT.
715 */
716 /**
717 * An implementation of a
718 * [network-only]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#network-only}
719 * request strategy.
720 *
721 * This class is useful if you want to take advantage of any
722 * [Workbox plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}.
723 *
724 * If the network request fails, this will throw a `WorkboxError` exception.
725 *
726 * @memberof workbox.strategies
727 */
728
729 class NetworkOnly {
730 /**
731 * @param {Object} options
732 * @param {string} options.cacheName Cache name to store and retrieve
733 * requests. Defaults to cache names provided by
734 * [workbox-core]{@link workbox.core.cacheNames}.
735 * @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
736 * to use in conjunction with this caching strategy.
737 * @param {Object} options.fetchOptions Values passed along to the
738 * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
739 * of all fetch() requests made by this strategy.
740 */
741 constructor(options = {}) {
742 this._cacheName = cacheNames_mjs.cacheNames.getRuntimeName(options.cacheName);
743 this._plugins = options.plugins || [];
744 this._fetchOptions = options.fetchOptions || null;
745 }
746 /**
747 * This method will perform a request strategy and follows an API that
748 * will work with the
749 * [Workbox Router]{@link workbox.routing.Router}.
750 *
751 * @param {Object} options
752 * @param {Request} options.request The request to run this strategy for.
753 * @param {Event} [options.event] The event that triggered the request.
754 * @return {Promise<Response>}
755 */
756
757
758 async handle({
759 event,
760 request
761 }) {
762 return this.makeRequest({
763 event,
764 request: request || event.request
765 });
766 }
767 /**
768 * This method can be used to perform a make a standalone request outside the
769 * context of the [Workbox Router]{@link workbox.routing.Router}.
770 *
771 * See "[Advanced Recipes](https://developers.google.com/web/tools/workbox/guides/advanced-recipes#make-requests)"
772 * for more usage information.
773 *
774 * @param {Object} options
775 * @param {Request|string} options.request Either a
776 * [`Request`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Request}
777 * object, or a string URL, corresponding to the request to be made.
778 * @param {FetchEvent} [options.event] If provided, `event.waitUntil()` will
779 * be called automatically to extend the service worker's lifetime.
780 * @return {Promise<Response>}
781 */
782
783
784 async makeRequest({
785 event,
786 request
787 }) {
788 if (typeof request === 'string') {
789 request = new Request(request);
790 }
791
792 {
793 assert_mjs.assert.isInstance(request, Request, {
794 moduleName: 'workbox-strategies',
795 className: 'NetworkOnly',
796 funcName: 'handle',
797 paramName: 'request'
798 });
799 }
800
801 let error;
802 let response;
803
804 try {
805 response = await fetchWrapper_mjs.fetchWrapper.fetch({
806 request,
807 event,
808 fetchOptions: this._fetchOptions,
809 plugins: this._plugins
810 });
811 } catch (err) {
812 error = err;
813 }
814
815 {
816 logger_mjs.logger.groupCollapsed(messages.strategyStart('NetworkOnly', request));
817
818 if (response) {
819 logger_mjs.logger.log(`Got response from network.`);
820 } else {
821 logger_mjs.logger.log(`Unable to get a response from the network.`);
822 }
823
824 messages.printFinalResponse(response);
825 logger_mjs.logger.groupEnd();
826 }
827
828 if (!response) {
829 throw new WorkboxError_mjs.WorkboxError('no-response', {
830 url: request.url,
831 error
832 });
833 }
834
835 return response;
836 }
837
838 }
839
840 /*
841 Copyright 2018 Google LLC
842
843 Use of this source code is governed by an MIT-style
844 license that can be found in the LICENSE file or at
845 https://opensource.org/licenses/MIT.
846 */
847 /**
848 * An implementation of a
849 * [stale-while-revalidate]{@link https://developers.google.com/web/fundamentals/instant-and-offline/offline-cookbook/#stale-while-revalidate}
850 * request strategy.
851 *
852 * Resources are requested from both the cache and the network in parallel.
853 * The strategy will respond with the cached version if available, otherwise
854 * wait for the network response. The cache is updated with the network response
855 * with each successful request.
856 *
857 * By default, this strategy will cache responses with a 200 status code as
858 * well as [opaque responses]{@link https://developers.google.com/web/tools/workbox/guides/handle-third-party-requests}.
859 * Opaque responses are are cross-origin requests where the response doesn't
860 * support [CORS]{@link https://enable-cors.org/}.
861 *
862 * If the network request fails, and there is no cache match, this will throw
863 * a `WorkboxError` exception.
864 *
865 * @memberof workbox.strategies
866 */
867
868 class StaleWhileRevalidate {
869 /**
870 * @param {Object} options
871 * @param {string} options.cacheName Cache name to store and retrieve
872 * requests. Defaults to cache names provided by
873 * [workbox-core]{@link workbox.core.cacheNames}.
874 * @param {Array<Object>} options.plugins [Plugins]{@link https://developers.google.com/web/tools/workbox/guides/using-plugins}
875 * to use in conjunction with this caching strategy.
876 * @param {Object} options.fetchOptions Values passed along to the
877 * [`init`](https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch#Parameters)
878 * of all fetch() requests made by this strategy.
879 * @param {Object} options.matchOptions [`CacheQueryOptions`](https://w3c.github.io/ServiceWorker/#dictdef-cachequeryoptions)
880 */
881 constructor(options = {}) {
882 this._cacheName = cacheNames_mjs.cacheNames.getRuntimeName(options.cacheName);
883 this._plugins = options.plugins || [];
884
885 if (options.plugins) {
886 let isUsingCacheWillUpdate = options.plugins.some(plugin => !!plugin.cacheWillUpdate);
887 this._plugins = isUsingCacheWillUpdate ? options.plugins : [cacheOkAndOpaquePlugin, ...options.plugins];
888 } else {
889 // No plugins passed in, use the default plugin.
890 this._plugins = [cacheOkAndOpaquePlugin];
891 }
892
893 this._fetchOptions = options.fetchOptions || null;
894 this._matchOptions = options.matchOptions || null;
895 }
896 /**
897 * This method will perform a request strategy and follows an API that
898 * will work with the
899 * [Workbox Router]{@link workbox.routing.Router}.
900 *
901 * @param {Object} options
902 * @param {Request} options.request The request to run this strategy for.
903 * @param {Event} [options.event] The event that triggered the request.
904 * @return {Promise<Response>}
905 */
906
907
908 async handle({
909 event,
910 request
911 }) {
912 return this.makeRequest({
913 event,
914 request: request || event.request
915 });
916 }
917 /**
918 * This method can be used to perform a make a standalone request outside the
919 * context of the [Workbox Router]{@link workbox.routing.Router}.
920 *
921 * See "[Advanced Recipes](https://developers.google.com/web/tools/workbox/guides/advanced-recipes#make-requests)"
922 * for more usage information.
923 *
924 * @param {Object} options
925 * @param {Request|string} options.request Either a
926 * [`Request`]{@link https://developer.mozilla.org/en-US/docs/Web/API/Request}
927 * object, or a string URL, corresponding to the request to be made.
928 * @param {FetchEvent} [options.event] If provided, `event.waitUntil()` will
929 * be called automatically to extend the service worker's lifetime.
930 * @return {Promise<Response>}
931 */
932
933
934 async makeRequest({
935 event,
936 request
937 }) {
938 const logs = [];
939
940 if (typeof request === 'string') {
941 request = new Request(request);
942 }
943
944 {
945 assert_mjs.assert.isInstance(request, Request, {
946 moduleName: 'workbox-strategies',
947 className: 'StaleWhileRevalidate',
948 funcName: 'handle',
949 paramName: 'request'
950 });
951 }
952
953 const fetchAndCachePromise = this._getFromNetwork({
954 request,
955 event
956 });
957
958 let response = await cacheWrapper_mjs.cacheWrapper.match({
959 cacheName: this._cacheName,
960 request,
961 event,
962 matchOptions: this._matchOptions,
963 plugins: this._plugins
964 });
965 let error;
966
967 if (response) {
968 {
969 logs.push(`Found a cached response in the '${this._cacheName}'` + ` cache. Will update with the network response in the background.`);
970 }
971
972 if (event) {
973 try {
974 event.waitUntil(fetchAndCachePromise);
975 } catch (error) {
976 {
977 logger_mjs.logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache for '${getFriendlyURL_mjs.getFriendlyURL(request.url)}'.`);
978 }
979 }
980 }
981 } else {
982 {
983 logs.push(`No response found in the '${this._cacheName}' cache. ` + `Will wait for the network response.`);
984 }
985
986 try {
987 response = await fetchAndCachePromise;
988 } catch (err) {
989 error = err;
990 }
991 }
992
993 {
994 logger_mjs.logger.groupCollapsed(messages.strategyStart('StaleWhileRevalidate', request));
995
996 for (let log of logs) {
997 logger_mjs.logger.log(log);
998 }
999
1000 messages.printFinalResponse(response);
1001 logger_mjs.logger.groupEnd();
1002 }
1003
1004 if (!response) {
1005 throw new WorkboxError_mjs.WorkboxError('no-response', {
1006 url: request.url,
1007 error
1008 });
1009 }
1010
1011 return response;
1012 }
1013 /**
1014 * @param {Object} options
1015 * @param {Request} options.request
1016 * @param {Event} [options.event]
1017 * @return {Promise<Response>}
1018 *
1019 * @private
1020 */
1021
1022
1023 async _getFromNetwork({
1024 request,
1025 event
1026 }) {
1027 const response = await fetchWrapper_mjs.fetchWrapper.fetch({
1028 request,
1029 event,
1030 fetchOptions: this._fetchOptions,
1031 plugins: this._plugins
1032 });
1033 const cachePutPromise = cacheWrapper_mjs.cacheWrapper.put({
1034 cacheName: this._cacheName,
1035 request,
1036 response: response.clone(),
1037 event,
1038 plugins: this._plugins
1039 });
1040
1041 if (event) {
1042 try {
1043 event.waitUntil(cachePutPromise);
1044 } catch (error) {
1045 {
1046 logger_mjs.logger.warn(`Unable to ensure service worker stays alive when ` + `updating cache for '${getFriendlyURL_mjs.getFriendlyURL(request.url)}'.`);
1047 }
1048 }
1049 }
1050
1051 return response;
1052 }
1053
1054 }
1055
1056 /*
1057 Copyright 2018 Google LLC
1058
1059 Use of this source code is governed by an MIT-style
1060 license that can be found in the LICENSE file or at
1061 https://opensource.org/licenses/MIT.
1062 */
1063 const mapping = {
1064 cacheFirst: CacheFirst,
1065 cacheOnly: CacheOnly,
1066 networkFirst: NetworkFirst,
1067 networkOnly: NetworkOnly,
1068 staleWhileRevalidate: StaleWhileRevalidate
1069 };
1070
1071 const deprecate = strategy => {
1072 const StrategyCtr = mapping[strategy];
1073 return options => {
1074 {
1075 const strategyCtrName = strategy[0].toUpperCase() + strategy.slice(1);
1076 logger_mjs.logger.warn(`The 'workbox.strategies.${strategy}()' function has been ` + `deprecated and will be removed in a future version of Workbox.\n` + `Please use 'new workbox.strategies.${strategyCtrName}()' instead.`);
1077 }
1078
1079 return new StrategyCtr(options);
1080 };
1081 };
1082 /**
1083 * @function workbox.strategies.cacheFirst
1084 * @param {Object} options See the {@link workbox.strategies.CacheFirst}
1085 * constructor for more info.
1086 * @deprecated since v4.0.0
1087 */
1088
1089
1090 const cacheFirst = deprecate('cacheFirst');
1091 /**
1092 * @function workbox.strategies.cacheOnly
1093 * @param {Object} options See the {@link workbox.strategies.CacheOnly}
1094 * constructor for more info.
1095 * @deprecated since v4.0.0
1096 */
1097
1098 const cacheOnly = deprecate('cacheOnly');
1099 /**
1100 * @function workbox.strategies.networkFirst
1101 * @param {Object} options See the {@link workbox.strategies.NetworkFirst}
1102 * constructor for more info.
1103 * @deprecated since v4.0.0
1104 */
1105
1106 const networkFirst = deprecate('networkFirst');
1107 /**
1108 * @function workbox.strategies.networkOnly
1109 * @param {Object} options See the {@link workbox.strategies.NetworkOnly}
1110 * constructor for more info.
1111 * @deprecated since v4.0.0
1112 */
1113
1114 const networkOnly = deprecate('networkOnly');
1115 /**
1116 * @function workbox.strategies.staleWhileRevalidate
1117 * @param {Object} options See the
1118 * {@link workbox.strategies.StaleWhileRevalidate} constructor for more info.
1119 * @deprecated since v4.0.0
1120 */
1121
1122 const staleWhileRevalidate = deprecate('staleWhileRevalidate');
1123
1124 exports.CacheFirst = CacheFirst;
1125 exports.CacheOnly = CacheOnly;
1126 exports.NetworkFirst = NetworkFirst;
1127 exports.NetworkOnly = NetworkOnly;
1128 exports.StaleWhileRevalidate = StaleWhileRevalidate;
1129 exports.cacheFirst = cacheFirst;
1130 exports.cacheOnly = cacheOnly;
1131 exports.networkFirst = networkFirst;
1132 exports.networkOnly = networkOnly;
1133 exports.staleWhileRevalidate = staleWhileRevalidate;
1134
1135 return exports;
1136
1137}({}, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private, workbox.core._private));
1138