UNPKG

38.6 kBJavaScriptView Raw
1this.workbox = this.workbox || {};
2this.workbox.precaching = (function (DBWrapper_mjs,logger_mjs,cacheNames_mjs,WorkboxError_mjs,fetchWrapper_mjs,cacheWrapper_mjs,assert_mjs,getFriendlyURL_mjs) {
3 'use strict';
4
5 try {
6 self.workbox.v['workbox:precaching:3.6.2'] = 1;
7 } catch (e) {} // eslint-disable-line
8
9 /*
10 Copyright 2017 Google Inc.
11
12 Licensed under the Apache License, Version 2.0 (the "License");
13 you may not use this file except in compliance with the License.
14 You may obtain a copy of the License at
15
16 https://www.apache.org/licenses/LICENSE-2.0
17
18 Unless required by applicable law or agreed to in writing, software
19 distributed under the License is distributed on an "AS IS" BASIS,
20 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 See the License for the specific language governing permissions and
22 limitations under the License.
23 */
24
25 /**
26 * Used as a consistent way of referencing a URL to precache.
27 *
28 * @private
29 * @memberof module:workbox-precaching
30 */
31 class PrecacheEntry {
32 /**
33 * This class ensures all cache list entries are consistent and
34 * adds cache busting if required.
35 *
36 * @param {*} originalInput
37 * @param {string} url
38 * @param {string} revision
39 * @param {boolean} shouldCacheBust
40 */
41 constructor(originalInput, url, revision, shouldCacheBust) {
42 this._originalInput = originalInput;
43 this._entryId = url;
44 this._revision = revision;
45 const requestAsCacheKey = new Request(url, { credentials: 'same-origin' });
46 this._cacheRequest = requestAsCacheKey;
47 this._networkRequest = shouldCacheBust ? this._cacheBustRequest(requestAsCacheKey) : requestAsCacheKey;
48 }
49
50 /**
51 * This method will either use Request.cache option OR append a cache
52 * busting parameter to the URL.
53 *
54 * @param {Request} request The request to cache bust
55 * @return {Request} A cachebusted Request
56 *
57 * @private
58 */
59 _cacheBustRequest(request) {
60 let url = request.url;
61 const requestOptions = {
62 credentials: 'same-origin'
63 };
64 if ('cache' in Request.prototype) {
65 // Make use of the Request cache mode where we can.
66 // Reload skips the HTTP cache for outgoing requests and updates
67 // the cache with the returned response.
68 requestOptions.cache = 'reload';
69 } else {
70 const parsedURL = new URL(url, location);
71
72 // This is done so the minifier can mangle 'global.encodeURIComponent'
73 const _encodeURIComponent = encodeURIComponent;
74
75 parsedURL.search += (parsedURL.search ? '&' : '') + _encodeURIComponent(`_workbox-cache-bust`) + '=' + _encodeURIComponent(this._revision);
76 url = parsedURL.toString();
77 }
78
79 return new Request(url, requestOptions);
80 }
81 }
82
83 /*
84 Copyright 2017 Google Inc.
85
86 Licensed under the Apache License, Version 2.0 (the "License");
87 you may not use this file except in compliance with the License.
88 You may obtain a copy of the License at
89
90 https://www.apache.org/licenses/LICENSE-2.0
91
92 Unless required by applicable law or agreed to in writing, software
93 distributed under the License is distributed on an "AS IS" BASIS,
94 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
95 See the License for the specific language governing permissions and
96 limitations under the License.
97 */
98
99 // Allows minifier to mangle this name
100 const REVISON_IDB_FIELD = 'revision';
101 const URL_IDB_FIELD = 'url';
102 const DB_STORE_NAME = 'precached-details-models';
103 /**
104 * This model will track the relevant information of entries that
105 * are cached and their matching revision details.
106 *
107 * @private
108 */
109 class PrecachedDetailsModel {
110 /**
111 * Construct a new model for a specific cache.
112 *
113 * @param {string} dbName
114 * @private
115 */
116 constructor(dbName) {
117 // This ensures the db name contains only letters, numbers, '-', '_' and '$'
118 const filteredDBName = dbName.replace(/[^\w-]/g, '_');
119 this._db = new DBWrapper_mjs.DBWrapper(filteredDBName, 2, {
120 onupgradeneeded: this._handleUpgrade
121 });
122 }
123
124 /**
125 * Should perform an upgrade of indexedDB.
126 *
127 * @param {Event} evt
128 *
129 * @private
130 */
131 _handleUpgrade(evt) {
132 const db = evt.target.result;
133 if (evt.oldVersion < 2) {
134 // IndexedDB version 1 used both 'workbox-precaching' and
135 // 'precached-details-model' before upgrading to version 2.
136 // Delete them and create a new store with latest schema.
137 if (db.objectStoreNames.contains('workbox-precaching')) {
138 db.deleteObjectStore('workbox-precaching');
139 }
140 if (db.objectStoreNames.contains(DB_STORE_NAME)) {
141 db.deleteObjectStore(DB_STORE_NAME);
142 }
143 }
144 db.createObjectStore(DB_STORE_NAME);
145 }
146
147 /**
148 * Check if an entry is already cached. Returns false if
149 * the entry isn't cached or the revision has changed.
150 *
151 * @param {string} cacheName
152 * @param {PrecacheEntry} precacheEntry
153 * @return {boolean}
154 *
155 * @private
156 */
157 _isEntryCached(cacheName, precacheEntry) {
158 var _this = this;
159
160 return babelHelpers.asyncToGenerator(function* () {
161 const revisionDetails = yield _this._getRevision(precacheEntry._entryId);
162 if (revisionDetails !== precacheEntry._revision) {
163 return false;
164 }
165
166 const openCache = yield caches.open(cacheName);
167 const cachedResponse = yield openCache.match(precacheEntry._cacheRequest);
168 return !!cachedResponse;
169 })();
170 }
171
172 /**
173 * @return {Promise<Array>}
174 *
175 * @private
176 */
177 _getAllEntries() {
178 var _this2 = this;
179
180 return babelHelpers.asyncToGenerator(function* () {
181 return yield _this2._db.getAllMatching(DB_STORE_NAME, {
182 includeKeys: true
183 });
184 })();
185 }
186
187 /**
188 * Get the current revision details.
189 *
190 * @param {Object} entryId
191 * @return {Promise<string|null>}
192 *
193 * @private
194 */
195 _getRevision(entryId) {
196 var _this3 = this;
197
198 return babelHelpers.asyncToGenerator(function* () {
199 const data = yield _this3._db.get(DB_STORE_NAME, entryId);
200 return data ? data[REVISON_IDB_FIELD] : null;
201 })();
202 }
203
204 /**
205 * Add an entry to the details model.
206 *
207 * @param {PrecacheEntry} precacheEntry
208 *
209 * @private
210 */
211 _addEntry(precacheEntry) {
212 var _this4 = this;
213
214 return babelHelpers.asyncToGenerator(function* () {
215 yield _this4._db.put(DB_STORE_NAME, {
216 [REVISON_IDB_FIELD]: precacheEntry._revision,
217 [URL_IDB_FIELD]: precacheEntry._cacheRequest.url
218 }, precacheEntry._entryId);
219 })();
220 }
221
222 /**
223 * Delete entry from details model.
224 *
225 * @param {string} entryId
226 *
227 * @private
228 */
229 _deleteEntry(entryId) {
230 var _this5 = this;
231
232 return babelHelpers.asyncToGenerator(function* () {
233 yield _this5._db.delete(DB_STORE_NAME, entryId);
234 })();
235 }
236 }
237
238 /*
239 Copyright 2017 Google Inc.
240
241 Licensed under the Apache License, Version 2.0 (the "License");
242 you may not use this file except in compliance with the License.
243 You may obtain a copy of the License at
244
245 https://www.apache.org/licenses/LICENSE-2.0
246
247 Unless required by applicable law or agreed to in writing, software
248 distributed under the License is distributed on an "AS IS" BASIS,
249 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
250 See the License for the specific language governing permissions and
251 limitations under the License.
252 */
253
254 /**
255 * This method will print out a warning if a precache entry doesn't have
256 * a `revision` value.
257 *
258 * This is common if the asset if revisioned in the url like `index.1234.css`.
259 *
260 * @param {Map} entriesMap
261 *
262 * @private
263 * @memberof module:workbox-preaching
264 */
265 var showWarningsIfNeeded = (entriesMap => {
266 const urlOnlyEntries = [];
267 entriesMap.forEach(entry => {
268 if (typeof entry === 'string' || !entry._originalInput.revision) {
269 urlOnlyEntries.push(entry._originalInput);
270 }
271 });
272
273 if (urlOnlyEntries.length === 0) {
274 // No warnings needed.
275 return;
276 }
277
278 logger_mjs.logger.groupCollapsed('Are your precached assets revisioned?');
279
280 const urlsList = urlOnlyEntries.map(urlOnlyEntry => {
281 return ` - ${JSON.stringify(urlOnlyEntry)}`;
282 }).join(`\n`);
283
284 logger_mjs.logger.warn(`The following precache entries might not be revisioned:` + `\n\n` + urlsList + `\n\n`);
285
286 logger_mjs.logger.unprefixed.warn(`You can learn more about why this might be a ` + `problem here: https://developers.google.com/web/tools/workbox/modules/workbox-precaching`);
287
288 logger_mjs.logger.groupEnd();
289 });
290
291 /*
292 Copyright 2017 Google Inc.
293
294 Licensed under the Apache License, Version 2.0 (the "License");
295 you may not use this file except in compliance with the License.
296 You may obtain a copy of the License at
297
298 https://www.apache.org/licenses/LICENSE-2.0
299
300 Unless required by applicable law or agreed to in writing, software
301 distributed under the License is distributed on an "AS IS" BASIS,
302 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
303 See the License for the specific language governing permissions and
304 limitations under the License.
305 */
306
307 /**
308 * @param {string} groupTitle
309 * @param {Array<PrecacheEntry>} entries
310 *
311 * @private
312 */
313 const _nestedGroup = (groupTitle, entries) => {
314 if (entries.length === 0) {
315 return;
316 }
317
318 logger_mjs.logger.groupCollapsed(groupTitle);
319
320 entries.forEach(entry => {
321 logger_mjs.logger.log(entry._originalInput);
322 });
323
324 logger_mjs.logger.groupEnd();
325 };
326
327 /**
328 * @param {Array<Object>} entriesToPrecache
329 * @param {Array<Object>} alreadyPrecachedEntries
330 *
331 * @private
332 * @memberof module:workbox-precachig
333 */
334 var printInstallDetails = ((entriesToPrecache, alreadyPrecachedEntries) => {
335 // Goal is to print the message:
336 // Precaching X files.
337 // Or:
338 // Precaching X files. Y files were cached and up-to-date.
339
340 const precachedCount = entriesToPrecache.length;
341 const alreadyPrecachedCount = alreadyPrecachedEntries.length;
342 let printText = `Precaching ${precachedCount} file${precachedCount === 1 ? '' : 's'}.`;
343 if (alreadyPrecachedCount > 0) {
344 printText += ` ${alreadyPrecachedCount} ` + `file${alreadyPrecachedCount === 1 ? ' is' : 's are'} already cached.`;
345 }
346
347 logger_mjs.logger.groupCollapsed(printText);
348
349 _nestedGroup(`View precached URLs.`, entriesToPrecache);
350 _nestedGroup(`View URLs that were already precached.`, alreadyPrecachedEntries);
351 logger_mjs.logger.groupEnd();
352 });
353
354 /*
355 Copyright 2017 Google Inc.
356
357 Licensed under the Apache License, Version 2.0 (the "License");
358 you may not use this file except in compliance with the License.
359 You may obtain a copy of the License at
360
361 https://www.apache.org/licenses/LICENSE-2.0
362
363 Unless required by applicable law or agreed to in writing, software
364 distributed under the License is distributed on an "AS IS" BASIS,
365 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
366 See the License for the specific language governing permissions and
367 limitations under the License.
368 */
369
370 const logGroup = (groupTitle, urls) => {
371 logger_mjs.logger.groupCollapsed(groupTitle);
372
373 urls.forEach(url => {
374 logger_mjs.logger.log(url);
375 });
376
377 logger_mjs.logger.groupEnd();
378 };
379
380 /**
381 * @param {Array<string>} deletedCacheRequests
382 * @param {Array<string>} deletedRevisionDetails
383 *
384 * @private
385 * @memberof module:workbox-precachig
386 */
387 var printCleanupDetails = ((deletedCacheRequests, deletedRevisionDetails) => {
388 if (deletedCacheRequests.length === 0 && deletedRevisionDetails.length === 0) {
389 return;
390 }
391
392 const cacheDeleteCount = deletedCacheRequests.length;
393 const revisionDeleteCount = deletedRevisionDetails.length;
394
395 const cacheDeleteText = `${cacheDeleteCount} cached ` + `request${cacheDeleteCount === 1 ? ' was' : 's were'} deleted`;
396 const revisionDeleteText = `${revisionDeleteCount} ` + `${revisionDeleteCount === 1 ? 'entry' : 'entries'} ` + `${revisionDeleteCount === 1 ? 'was' : 'were'} deleted from IndexedDB.`;
397
398 logger_mjs.logger.groupCollapsed(`During precaching cleanup, ${cacheDeleteText} and ${revisionDeleteText}`);
399
400 logGroup('Deleted Cache Requests', deletedCacheRequests);
401 logGroup('Revision Details Deleted from DB', deletedRevisionDetails);
402
403 logger_mjs.logger.groupEnd();
404 });
405
406 /*
407 Copyright 2017 Google Inc.
408
409 Licensed under the Apache License, Version 2.0 (the "License");
410 you may not use this file except in compliance with the License.
411 You may obtain a copy of the License at
412
413 https://www.apache.org/licenses/LICENSE-2.0
414
415 Unless required by applicable law or agreed to in writing, software
416 distributed under the License is distributed on an "AS IS" BASIS,
417 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
418 See the License for the specific language governing permissions and
419 limitations under the License.
420 */
421
422 /**
423 * @param {Response} response
424 * @return {Response}
425 *
426 * @private
427 * @memberof module:workbox-precachig
428 */
429 const cleanRedirect = (() => {
430 var _ref = babelHelpers.asyncToGenerator(function* (response) {
431 const clonedResponse = response.clone();
432
433 // Not all browsers support the Response.body stream, so fall back
434 // to reading the entire body into memory as a blob.
435 const bodyPromise = 'body' in clonedResponse ? Promise.resolve(clonedResponse.body) : clonedResponse.blob();
436
437 const body = yield bodyPromise;
438
439 // new Response() is happy when passed either a stream or a Blob.
440 return new Response(body, ['headers', 'status', 'statusText'].map(function (key) {
441 return clonedResponse[key];
442 }));
443 });
444
445 return function cleanRedirect(_x) {
446 return _ref.apply(this, arguments);
447 };
448 })();
449
450 /*
451 Copyright 2017 Google Inc.
452
453 Licensed under the Apache License, Version 2.0 (the "License");
454 you may not use this file except in compliance with the License.
455 You may obtain a copy of the License at
456
457 https://www.apache.org/licenses/LICENSE-2.0
458
459 Unless required by applicable law or agreed to in writing, software
460 distributed under the License is distributed on an "AS IS" BASIS,
461 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
462 See the License for the specific language governing permissions and
463 limitations under the License.
464 */
465
466 /**
467 * Performs efficient precaching of assets.
468 *
469 * @memberof workbox.precaching
470 */
471 class PrecacheController {
472 /**
473 * Create a new PrecacheController.
474 *
475 * @param {string} cacheName
476 */
477 constructor(cacheName) {
478 this._cacheName = cacheNames_mjs.cacheNames.getPrecacheName(cacheName);
479 this._entriesToCacheMap = new Map();
480 this._precacheDetailsModel = new PrecachedDetailsModel(this._cacheName);
481 }
482
483 /**
484 * This method will add items to the precache list, removing duplicates
485 * and ensuring the information is valid.
486 *
487 * @param {
488 * Array<module:workbox-precaching.PrecacheController.PrecacheEntry|string>
489 * } entries Array of entries to
490 * precache.
491 */
492 addToCacheList(entries) {
493 {
494 assert_mjs.assert.isArray(entries, {
495 moduleName: 'workbox-precaching',
496 className: 'PrecacheController',
497 funcName: 'addToCacheList',
498 paramName: 'entries'
499 });
500 }
501
502 entries.map(userEntry => {
503 this._addEntryToCacheList(this._parseEntry(userEntry));
504 });
505 }
506
507 /**
508 * This method returns a precache entry.
509 *
510 * @private
511 * @param {string|Object} input
512 * @return {PrecacheEntry}
513 */
514 _parseEntry(input) {
515 switch (typeof input) {
516 case 'string':
517 {
518 {
519 if (input.length === 0) {
520 throw new WorkboxError_mjs.WorkboxError('add-to-cache-list-unexpected-type', {
521 entry: input
522 });
523 }
524 }
525
526 return new PrecacheEntry(input, input, input);
527 }
528 case 'object':
529 {
530 {
531 if (!input || !input.url) {
532 throw new WorkboxError_mjs.WorkboxError('add-to-cache-list-unexpected-type', {
533 entry: input
534 });
535 }
536 }
537
538 return new PrecacheEntry(input, input.url, input.revision || input.url, !!input.revision);
539 }
540 default:
541 throw new WorkboxError_mjs.WorkboxError('add-to-cache-list-unexpected-type', {
542 entry: input
543 });
544 }
545 }
546
547 /**
548 * Adds an entry to the precache list, accounting for possible duplicates.
549 *
550 * @private
551 * @param {PrecacheEntry} entryToAdd
552 */
553 _addEntryToCacheList(entryToAdd) {
554 // Check if the entry is already part of the map
555 const existingEntry = this._entriesToCacheMap.get(entryToAdd._entryId);
556 if (!existingEntry) {
557 this._entriesToCacheMap.set(entryToAdd._entryId, entryToAdd);
558 return;
559 }
560
561 // Duplicates are fine, but make sure the revision information
562 // is the same.
563 if (existingEntry._revision !== entryToAdd._revision) {
564 throw new WorkboxError_mjs.WorkboxError('add-to-cache-list-conflicting-entries', {
565 firstEntry: existingEntry._originalInput,
566 secondEntry: entryToAdd._originalInput
567 });
568 }
569 }
570
571 /**
572 * Call this method from a service work install event to start
573 * precaching assets.
574 *
575 * @param {Object} options
576 * @param {boolean} [options.suppressWarnings] Suppress warning messages.
577 * @param {Event} [options.event] The install event (if needed).
578 * @param {Array<Object>} [options.plugins] Plugins to be used for fetching
579 * and caching during install.
580 * @return {Promise<workbox.precaching.InstallResult>}
581 */
582 install({ suppressWarnings = false, event, plugins } = {}) {
583 var _this = this;
584
585 return babelHelpers.asyncToGenerator(function* () {
586 {
587 if (suppressWarnings !== true) {
588 showWarningsIfNeeded(_this._entriesToCacheMap);
589 }
590
591 if (plugins) {
592 assert_mjs.assert.isArray(plugins, {
593 moduleName: 'workbox-precaching',
594 className: 'PrecacheController',
595 funcName: 'install',
596 paramName: 'plugins'
597 });
598 }
599 }
600
601 // Empty the temporary cache.
602 // NOTE: We remove all entries instead of deleting the cache as the cache
603 // may be marked for deletion but still exist until a later stage
604 // resulting in unexpected behavior of being deletect when all references
605 // are dropped.
606 // https://github.com/GoogleChrome/workbox/issues/1368
607 const tempCache = yield caches.open(_this._getTempCacheName());
608 const requests = yield tempCache.keys();
609 yield Promise.all(requests.map(function (request) {
610 return tempCache.delete(request);
611 }));
612
613 const entriesToPrecache = [];
614 const entriesAlreadyPrecached = [];
615
616 for (const precacheEntry of _this._entriesToCacheMap.values()) {
617 if (yield _this._precacheDetailsModel._isEntryCached(_this._cacheName, precacheEntry)) {
618 entriesAlreadyPrecached.push(precacheEntry);
619 } else {
620 entriesToPrecache.push(precacheEntry);
621 }
622 }
623
624 // Wait for all requests to be cached.
625 yield Promise.all(entriesToPrecache.map(function (precacheEntry) {
626 return _this._cacheEntryInTemp({ event, plugins, precacheEntry });
627 }));
628
629 {
630 printInstallDetails(entriesToPrecache, entriesAlreadyPrecached);
631 }
632
633 return {
634 updatedEntries: entriesToPrecache,
635 notUpdatedEntries: entriesAlreadyPrecached
636 };
637 })();
638 }
639
640 /**
641 * Takes the current set of temporary files and moves them to the final
642 * cache, deleting the temporary cache once copying is complete.
643 *
644 * @param {Object} options
645 * @param {Array<Object>} options.plugins Plugins to be used for fetching
646 * and caching during install.
647 * @return {
648 * Promise<workbox.precaching.CleanupResult>}
649 * Resolves with an object containing details of the deleted cache requests
650 * and precache revision details.
651 */
652 activate(options = {}) {
653 var _this2 = this;
654
655 return babelHelpers.asyncToGenerator(function* () {
656 const tempCache = yield caches.open(_this2._getTempCacheName());
657
658 const requests = yield tempCache.keys();
659 // Process each request/response one at a time, deleting the temporary entry
660 // when done, to help avoid triggering quota errors.
661 for (const request of requests) {
662 const response = yield tempCache.match(request);
663 yield cacheWrapper_mjs.cacheWrapper.put({
664 cacheName: _this2._cacheName,
665 request,
666 response,
667 plugins: options.plugins
668 });
669 yield tempCache.delete(request);
670 }
671
672 return _this2._cleanup();
673 })();
674 }
675
676 /**
677 * Returns the name of the temporary cache.
678 *
679 * @return {string}
680 *
681 * @private
682 */
683 _getTempCacheName() {
684 return `${this._cacheName}-temp`;
685 }
686
687 /**
688 * Requests the entry and saves it to the cache if the response
689 * is valid.
690 *
691 * @private
692 * @param {Object} options
693 * @param {BaseCacheEntry} options.precacheEntry The entry to fetch and cache.
694 * @param {Event} [options.event] The install event (if passed).
695 * @param {Array<Object>} [options.plugins] An array of plugins to apply to
696 * fetch and caching.
697 * @return {Promise<boolean>} Returns a promise that resolves once the entry
698 * has been fetched and cached or skipped if no update is needed. The
699 * promise resolves with true if the entry was cached / updated and
700 * false if the entry is already cached and up-to-date.
701 */
702 _cacheEntryInTemp({ precacheEntry, event, plugins }) {
703 var _this3 = this;
704
705 return babelHelpers.asyncToGenerator(function* () {
706 let response = yield fetchWrapper_mjs.fetchWrapper.fetch({
707 request: precacheEntry._networkRequest,
708 event,
709 fetchOptions: null,
710 plugins
711 });
712
713 if (response.redirected) {
714 response = yield cleanRedirect(response);
715 }
716
717 yield cacheWrapper_mjs.cacheWrapper.put({
718 cacheName: _this3._getTempCacheName(),
719 request: precacheEntry._cacheRequest,
720 response,
721 event,
722 plugins
723 });
724
725 yield _this3._precacheDetailsModel._addEntry(precacheEntry);
726
727 return true;
728 })();
729 }
730
731 /**
732 * Compare the URLs and determines which assets are no longer required
733 * in the cache.
734 *
735 * This should be called in the service worker activate event.
736 *
737 * @return {
738 * Promise<workbox.precaching.CleanupResult>}
739 * Resolves with an object containing details of the deleted cache requests
740 * and precache revision details.
741 *
742 * @private
743 */
744 _cleanup() {
745 var _this4 = this;
746
747 return babelHelpers.asyncToGenerator(function* () {
748 const expectedCacheUrls = [];
749 _this4._entriesToCacheMap.forEach(function (entry) {
750 const fullUrl = new URL(entry._cacheRequest.url, location).toString();
751 expectedCacheUrls.push(fullUrl);
752 });
753
754 const [deletedCacheRequests, deletedRevisionDetails] = yield Promise.all([_this4._cleanupCache(expectedCacheUrls), _this4._cleanupDetailsModel(expectedCacheUrls)]);
755
756 {
757 printCleanupDetails(deletedCacheRequests, deletedRevisionDetails);
758 }
759
760 return {
761 deletedCacheRequests,
762 deletedRevisionDetails
763 };
764 })();
765 }
766
767 /**
768 * Goes through all the cache entries and removes any that are
769 * outdated.
770 *
771 * @private
772 * @param {Array<string>} expectedCacheUrls Array of URLs that are
773 * expected to be cached.
774 * @return {Promise<Array<string>>} Resolves to an array of URLs
775 * of cached requests that were deleted.
776 */
777 _cleanupCache(expectedCacheUrls) {
778 var _this5 = this;
779
780 return babelHelpers.asyncToGenerator(function* () {
781 if (!(yield caches.has(_this5._cacheName))) {
782 // Cache doesn't exist, so nothing to delete
783 return [];
784 }
785
786 const cache = yield caches.open(_this5._cacheName);
787 const cachedRequests = yield cache.keys();
788 const cachedRequestsToDelete = cachedRequests.filter(function (cachedRequest) {
789 return !expectedCacheUrls.includes(new URL(cachedRequest.url, location).toString());
790 });
791
792 yield Promise.all(cachedRequestsToDelete.map(function (cacheUrl) {
793 return cache.delete(cacheUrl);
794 }));
795
796 return cachedRequestsToDelete.map(function (request) {
797 return request.url;
798 });
799 })();
800 }
801
802 /**
803 * Goes through all entries in indexedDB and removes any that are outdated.
804 *
805 * @private
806 * @param {Array<string>} expectedCacheUrls Array of URLs that are
807 * expected to be cached.
808 * @return {Promise<Array<string>>} Resolves to an array of URLs removed
809 * from indexedDB.
810 */
811 _cleanupDetailsModel(expectedCacheUrls) {
812 var _this6 = this;
813
814 return babelHelpers.asyncToGenerator(function* () {
815 const revisionedEntries = yield _this6._precacheDetailsModel._getAllEntries();
816 const detailsToDelete = revisionedEntries.filter(function (entry) {
817 const fullUrl = new URL(entry.value.url, location).toString();
818 return !expectedCacheUrls.includes(fullUrl);
819 });
820
821 yield Promise.all(detailsToDelete.map(function (entry) {
822 return _this6._precacheDetailsModel._deleteEntry(entry.primaryKey);
823 }));
824 return detailsToDelete.map(function (entry) {
825 return entry.value.url;
826 });
827 })();
828 }
829
830 /**
831 * Returns an array of fully qualified URL's that will be precached.
832 *
833 * @return {Array<string>} An array of URLs.
834 */
835 getCachedUrls() {
836 return Array.from(this._entriesToCacheMap.keys()).map(url => new URL(url, location).href);
837 }
838 }
839
840 /*
841 Copyright 2017 Google Inc.
842
843 Licensed under the Apache License, Version 2.0 (the "License");
844 you may not use this file except in compliance with the License.
845 You may obtain a copy of the License at
846
847 https://www.apache.org/licenses/LICENSE-2.0
848
849 Unless required by applicable law or agreed to in writing, software
850 distributed under the License is distributed on an "AS IS" BASIS,
851 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
852 See the License for the specific language governing permissions and
853 limitations under the License.
854 */
855
856 var publicAPI = /*#__PURE__*/Object.freeze({
857 PrecacheController: PrecacheController
858 });
859
860 /*
861 Copyright 2017 Google Inc.
862
863 Licensed under the Apache License, Version 2.0 (the "License");
864 you may not use this file except in compliance with the License.
865 You may obtain a copy of the License at
866
867 https://www.apache.org/licenses/LICENSE-2.0
868
869 Unless required by applicable law or agreed to in writing, software
870 distributed under the License is distributed on an "AS IS" BASIS,
871 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
872 See the License for the specific language governing permissions and
873 limitations under the License.
874 */
875
876 {
877 assert_mjs.assert.isSwEnv('workbox-precaching');
878 }
879
880 let installActivateListenersAdded = false;
881 let fetchListenersAdded = false;
882 let suppressWarnings = false;
883 let plugins = [];
884
885 const cacheName = cacheNames_mjs.cacheNames.getPrecacheName();
886 const precacheController = new PrecacheController(cacheName);
887
888 const _removeIgnoreUrlParams = (origUrlObject, ignoreUrlParametersMatching) => {
889 // Exclude initial '?'
890 const searchString = origUrlObject.search.slice(1);
891
892 // Split into an array of 'key=value' strings
893 const keyValueStrings = searchString.split('&');
894 const keyValuePairs = keyValueStrings.map(keyValueString => {
895 // Split each 'key=value' string into a [key, value] array
896 return keyValueString.split('=');
897 });
898 const filteredKeyValuesPairs = keyValuePairs.filter(keyValuePair => {
899 return ignoreUrlParametersMatching.every(ignoredRegex => {
900 // Return true iff the key doesn't match any of the regexes.
901 return !ignoredRegex.test(keyValuePair[0]);
902 });
903 });
904 const filteredStrings = filteredKeyValuesPairs.map(keyValuePair => {
905 // Join each [key, value] array into a 'key=value' string
906 return keyValuePair.join('=');
907 });
908
909 // Join the array of 'key=value' strings into a string with '&' in
910 // between each
911 const urlClone = new URL(origUrlObject);
912 urlClone.search = filteredStrings.join('&');
913 return urlClone;
914 };
915
916 /**
917 * This function will take the request URL and manipulate it based on the
918 * configuration options.
919 *
920 * @param {string} url
921 * @param {Object} options
922 * @return {string|null} Returns the URL in the cache that matches the request
923 * if available, other null.
924 *
925 * @private
926 */
927 const _getPrecachedUrl = (url, {
928 ignoreUrlParametersMatching = [/^utm_/],
929 directoryIndex = 'index.html',
930 cleanUrls = true,
931 urlManipulation = null
932 } = {}) => {
933 const urlObject = new URL(url, location);
934
935 // Change '/some-url#123' => '/some-url'
936 urlObject.hash = '';
937
938 const urlWithoutIgnoredParams = _removeIgnoreUrlParams(urlObject, ignoreUrlParametersMatching);
939
940 let urlsToAttempt = [
941 // Test the URL that was fetched
942 urlObject,
943 // Test the URL without search params
944 urlWithoutIgnoredParams];
945
946 // Test the URL with a directory index
947 if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith('/')) {
948 const directoryUrl = new URL(urlWithoutIgnoredParams);
949 directoryUrl.pathname += directoryIndex;
950 urlsToAttempt.push(directoryUrl);
951 }
952
953 // Test the URL with a '.html' extension
954 if (cleanUrls) {
955 const cleanUrl = new URL(urlWithoutIgnoredParams);
956 cleanUrl.pathname += '.html';
957 urlsToAttempt.push(cleanUrl);
958 }
959
960 if (urlManipulation) {
961 const additionalUrls = urlManipulation({ url: urlObject });
962 urlsToAttempt = urlsToAttempt.concat(additionalUrls);
963 }
964
965 const cachedUrls = precacheController.getCachedUrls();
966 for (const possibleUrl of urlsToAttempt) {
967 if (cachedUrls.indexOf(possibleUrl.href) !== -1) {
968 // It's a perfect match
969 {
970 logger_mjs.logger.debug(`Precaching found a match for ` + getFriendlyURL_mjs.getFriendlyURL(possibleUrl.toString()));
971 }
972 return possibleUrl.href;
973 }
974 }
975
976 return null;
977 };
978
979 const moduleExports = {};
980
981 /**
982 * Add items to the precache list, removing any duplicates and
983 * store the files in the
984 * ["precache cache"]{@link module:workbox-core.cacheNames} when the service
985 * worker installs.
986 *
987 * This method can be called multiple times.
988 *
989 * Please note: This method **will not** serve any of the cached files for you,
990 * it only precaches files. To respond to a network request you call
991 * [addRoute()]{@link module:workbox-precaching.addRoute}.
992 *
993 * If you have a single array of files to precache, you can just call
994 * [precacheAndRoute()]{@link module:workbox-precaching.precacheAndRoute}.
995 *
996 * @param {Array<Object|string>} entries Array of entries to precache.
997 *
998 * @alias workbox.precaching.precache
999 */
1000 moduleExports.precache = entries => {
1001 precacheController.addToCacheList(entries);
1002
1003 if (installActivateListenersAdded || entries.length <= 0) {
1004 return;
1005 }
1006
1007 installActivateListenersAdded = true;
1008 self.addEventListener('install', event => {
1009 event.waitUntil(precacheController.install({
1010 event,
1011 plugins,
1012 suppressWarnings
1013 }));
1014 });
1015 self.addEventListener('activate', event => {
1016 event.waitUntil(precacheController.activate({
1017 event,
1018 plugins
1019 }));
1020 });
1021 };
1022
1023 /**
1024 * Add a `fetch` listener to the service worker that will
1025 * respond to
1026 * [network requests]{@link https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests}
1027 * with precached assets.
1028 *
1029 * Requests for assets that aren't precached, the `FetchEvent` will not be
1030 * responded to, allowing the event to fall through to other `fetch` event
1031 * listeners.
1032 *
1033 * @param {Object} options
1034 * @param {string} [options.directoryIndex=index.html] The `directoryIndex` will
1035 * check cache entries for a URLs ending with '/' to see if there is a hit when
1036 * appending the `directoryIndex` value.
1037 * @param {Array<RegExp>} [options.ignoreUrlParametersMatching=[/^utm_/]] An
1038 * array of regex's to remove search params when looking for a cache match.
1039 * @param {boolean} [options.cleanUrls=true] The `cleanUrls` option will
1040 * check the cache for the URL with a `.html` added to the end of the end.
1041 * @param {workbox.precaching~urlManipulation} [options.urlManipulation]
1042 * This is a function that should take a URL and return an array of
1043 * alternative URL's that should be checked for precache matches.
1044 *
1045 * @alias workbox.precaching.addRoute
1046 */
1047 moduleExports.addRoute = options => {
1048 if (fetchListenersAdded) {
1049 // TODO: Throw error here.
1050 return;
1051 }
1052
1053 fetchListenersAdded = true;
1054 self.addEventListener('fetch', event => {
1055 const precachedUrl = _getPrecachedUrl(event.request.url, options);
1056 if (!precachedUrl) {
1057 {
1058 logger_mjs.logger.debug(`Precaching found no match for ` + getFriendlyURL_mjs.getFriendlyURL(event.request.url));
1059 }
1060 return;
1061 }
1062
1063 let responsePromise = caches.open(cacheName).then(cache => {
1064 return cache.match(precachedUrl);
1065 }).then(cachedResponse => {
1066 if (cachedResponse) {
1067 return cachedResponse;
1068 }
1069
1070 // Fall back to the network if we don't have a cached response (perhaps
1071 // due to manual cache cleanup).
1072 {
1073 logger_mjs.logger.debug(`The precached response for ` + `${getFriendlyURL_mjs.getFriendlyURL(precachedUrl)} in ${cacheName} was not found. ` + `Falling back to the network instead.`);
1074 }
1075
1076 return fetch(precachedUrl);
1077 });
1078
1079 {
1080 responsePromise = responsePromise.then(response => {
1081 // Workbox is going to handle the route.
1082 // print the routing details to the console.
1083 logger_mjs.logger.groupCollapsed(`Precaching is responding to: ` + getFriendlyURL_mjs.getFriendlyURL(event.request.url));
1084 logger_mjs.logger.log(`Serving the precached url: ${precachedUrl}`);
1085
1086 // The Request and Response objects contains a great deal of
1087 // information, hide it under a group in case developers want to see it.
1088 logger_mjs.logger.groupCollapsed(`View request details here.`);
1089 logger_mjs.logger.unprefixed.log(event.request);
1090 logger_mjs.logger.groupEnd();
1091
1092 logger_mjs.logger.groupCollapsed(`View response details here.`);
1093 logger_mjs.logger.unprefixed.log(response);
1094 logger_mjs.logger.groupEnd();
1095
1096 logger_mjs.logger.groupEnd();
1097 return response;
1098 });
1099 }
1100 event.respondWith(responsePromise);
1101 });
1102 };
1103
1104 /**
1105 * This method will add entries to the precache list and add a route to
1106 * respond to fetch events.
1107 *
1108 * This is a convenience method that will call
1109 * [precache()]{@link module:workbox-precaching.precache} and
1110 * [addRoute()]{@link module:workbox-precaching.addRoute} in a single call.
1111 *
1112 * @param {Array<Object|string>} entries Array of entries to precache.
1113 * @param {Object} options See
1114 * [addRoute() options]{@link module:workbox-precaching.addRoute}.
1115 *
1116 * @alias workbox.precaching.precacheAndRoute
1117 */
1118 moduleExports.precacheAndRoute = (entries, options) => {
1119 moduleExports.precache(entries);
1120 moduleExports.addRoute(options);
1121 };
1122
1123 /**
1124 * Warnings will be logged if any of the precached assets are entered without
1125 * a `revision` property. This is extremely dangerous if the URL's aren't
1126 * revisioned. However, the warnings can be supressed with this method.
1127 *
1128 * @param {boolean} suppress
1129 *
1130 * @alias workbox.precaching.suppressWarnings
1131 */
1132 moduleExports.suppressWarnings = suppress => {
1133 suppressWarnings = suppress;
1134 };
1135
1136 /**
1137 * Add plugins to precaching.
1138 *
1139 * @param {Array<Object>} newPlugins
1140 *
1141 * @alias workbox.precaching.addPlugins
1142 */
1143 moduleExports.addPlugins = newPlugins => {
1144 plugins = plugins.concat(newPlugins);
1145 };
1146
1147 /*
1148 Copyright 2017 Google Inc.
1149
1150 Licensed under the Apache License, Version 2.0 (the "License");
1151 you may not use this file except in compliance with the License.
1152 You may obtain a copy of the License at
1153
1154 https://www.apache.org/licenses/LICENSE-2.0
1155
1156 Unless required by applicable law or agreed to in writing, software
1157 distributed under the License is distributed on an "AS IS" BASIS,
1158 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1159 See the License for the specific language governing permissions and
1160 limitations under the License.
1161 */
1162
1163 const finalExport = Object.assign(moduleExports, publicAPI);
1164
1165 return finalExport;
1166
1167}(workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private));
1168
1169//# sourceMappingURL=workbox-precaching.dev.js.map