UNPKG

36.2 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
5try {
6 self.workbox.v['workbox:precaching:3.0.1'] = 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 */
31class 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
100const REVISON_IDB_FIELD = 'revision';
101const URL_IDB_FIELD = 'url';
102const 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 */
109class 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 */
265var 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 */
313const _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 */
334var 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
370const 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 */
387var 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 */
429const 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 */
471class 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 {Array<Object>} options.plugins Plugins to be used for fetching
578 * and caching during install.
579 * @return {
580 * Promise<workbox.precaching.InstallResult>}
581 */
582 install(options = {}) {
583 var _this = this;
584
585 return babelHelpers.asyncToGenerator(function* () {
586 {
587 if (options.suppressWarnings !== true) {
588 showWarningsIfNeeded(_this._entriesToCacheMap);
589 }
590
591 if (options.plugins) {
592 assert_mjs.assert.isArray(options.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(precacheEntry, options.plugins);
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 yield Promise.all(requests.map((() => {
660 var _ref = babelHelpers.asyncToGenerator(function* (request) {
661 const response = yield tempCache.match(request);
662 yield cacheWrapper_mjs.cacheWrapper.put(_this2._cacheName, request, response, options.plugins);
663 yield tempCache.delete(request);
664 });
665
666 return function (_x) {
667 return _ref.apply(this, arguments);
668 };
669 })()));
670
671 return _this2._cleanup();
672 })();
673 }
674
675 /**
676 * Returns the name of the temporary cache.
677 *
678 * @return {string}
679 *
680 * @private
681 */
682 _getTempCacheName() {
683 return `${this._cacheName}-temp`;
684 }
685
686 /**
687 * Requests the entry and saves it to the cache if the response
688 * is valid.
689 *
690 * @private
691 * @param {BaseCacheEntry} precacheEntry The entry to fetch and cache.
692 * @param {Array<Object>} plugins Array of plugins to apply to fetch and
693 * caching.
694 * @return {Promise<boolean>} Returns a promise that resolves once the entry
695 * has been fetched and cached or skipped if no update is needed. The
696 * promise resolves with true if the entry was cached / updated and
697 * false if the entry is already cached and up-to-date.
698 */
699 _cacheEntryInTemp(precacheEntry, plugins) {
700 var _this3 = this;
701
702 return babelHelpers.asyncToGenerator(function* () {
703 let response = yield fetchWrapper_mjs.fetchWrapper.fetch(precacheEntry._networkRequest, null, plugins);
704
705 if (response.redirected) {
706 response = yield cleanRedirect(response);
707 }
708
709 yield cacheWrapper_mjs.cacheWrapper.put(_this3._getTempCacheName(), precacheEntry._cacheRequest, response, plugins);
710
711 yield _this3._precacheDetailsModel._addEntry(precacheEntry);
712
713 return true;
714 })();
715 }
716
717 /**
718 * Compare the URLs and determines which assets are no longer required
719 * in the cache.
720 *
721 * This should be called in the service worker activate event.
722 *
723 * @return {
724 * Promise<workbox.precaching.CleanupResult>}
725 * Resolves with an object containing details of the deleted cache requests
726 * and precache revision details.
727 *
728 * @private
729 */
730 _cleanup() {
731 var _this4 = this;
732
733 return babelHelpers.asyncToGenerator(function* () {
734 const expectedCacheUrls = [];
735 _this4._entriesToCacheMap.forEach(function (entry) {
736 const fullUrl = new URL(entry._cacheRequest.url, location).toString();
737 expectedCacheUrls.push(fullUrl);
738 });
739
740 const [deletedCacheRequests, deletedRevisionDetails] = yield Promise.all([_this4._cleanupCache(expectedCacheUrls), _this4._cleanupDetailsModel(expectedCacheUrls)]);
741
742 {
743 printCleanupDetails(deletedCacheRequests, deletedRevisionDetails);
744 }
745
746 return {
747 deletedCacheRequests,
748 deletedRevisionDetails
749 };
750 })();
751 }
752
753 /**
754 * Goes through all the cache entries and removes any that are
755 * outdated.
756 *
757 * @private
758 * @param {Array<string>} expectedCacheUrls Array of URLs that are
759 * expected to be cached.
760 * @return {Promise<Array<string>>} Resolves to an array of URLs
761 * of cached requests that were deleted.
762 */
763 _cleanupCache(expectedCacheUrls) {
764 var _this5 = this;
765
766 return babelHelpers.asyncToGenerator(function* () {
767 if (!(yield caches.has(_this5._cacheName))) {
768 // Cache doesn't exist, so nothing to delete
769 return [];
770 }
771
772 const cache = yield caches.open(_this5._cacheName);
773 const cachedRequests = yield cache.keys();
774 const cachedRequestsToDelete = cachedRequests.filter(function (cachedRequest) {
775 return !expectedCacheUrls.includes(new URL(cachedRequest.url, location).toString());
776 });
777
778 yield Promise.all(cachedRequestsToDelete.map(function (cacheUrl) {
779 return cache.delete(cacheUrl);
780 }));
781
782 return cachedRequestsToDelete.map(function (request) {
783 return request.url;
784 });
785 })();
786 }
787
788 /**
789 * Goes through all entries in indexedDB and removes any that are outdated.
790 *
791 * @private
792 * @param {Array<string>} expectedCacheUrls Array of URLs that are
793 * expected to be cached.
794 * @return {Promise<Array<string>>} Resolves to an array of URLs removed
795 * from indexedDB.
796 */
797 _cleanupDetailsModel(expectedCacheUrls) {
798 var _this6 = this;
799
800 return babelHelpers.asyncToGenerator(function* () {
801 const revisionedEntries = yield _this6._precacheDetailsModel._getAllEntries();
802 const detailsToDelete = revisionedEntries.filter(function (entry) {
803 const fullUrl = new URL(entry.value.url, location).toString();
804 return !expectedCacheUrls.includes(fullUrl);
805 });
806
807 yield Promise.all(detailsToDelete.map(function (entry) {
808 return _this6._precacheDetailsModel._deleteEntry(entry.primaryKey);
809 }));
810 return detailsToDelete.map(function (entry) {
811 return entry.value.url;
812 });
813 })();
814 }
815
816 /**
817 * Returns an array of fully qualified URL's that will be precached.
818 *
819 * @return {Array<string>} An array of URLs.
820 */
821 getCachedUrls() {
822 return Array.from(this._entriesToCacheMap.keys()).map(url => new URL(url, location).href);
823 }
824}
825
826/*
827 Copyright 2017 Google Inc.
828
829 Licensed under the Apache License, Version 2.0 (the "License");
830 you may not use this file except in compliance with the License.
831 You may obtain a copy of the License at
832
833 https://www.apache.org/licenses/LICENSE-2.0
834
835 Unless required by applicable law or agreed to in writing, software
836 distributed under the License is distributed on an "AS IS" BASIS,
837 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
838 See the License for the specific language governing permissions and
839 limitations under the License.
840*/
841
842
843var publicAPI = Object.freeze({
844 PrecacheController: PrecacheController
845});
846
847/*
848 Copyright 2017 Google Inc.
849
850 Licensed under the Apache License, Version 2.0 (the "License");
851 you may not use this file except in compliance with the License.
852 You may obtain a copy of the License at
853
854 https://www.apache.org/licenses/LICENSE-2.0
855
856 Unless required by applicable law or agreed to in writing, software
857 distributed under the License is distributed on an "AS IS" BASIS,
858 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
859 See the License for the specific language governing permissions and
860 limitations under the License.
861*/
862
863{
864 assert_mjs.assert.isSwEnv('workbox-precaching');
865}
866
867let installActivateListenersAdded = false;
868let fetchListenersAdded = false;
869let suppressWarnings = false;
870let plugins = [];
871
872const cacheName = cacheNames_mjs.cacheNames.getPrecacheName();
873const precacheController = new PrecacheController(cacheName);
874
875const _removeIgnoreUrlParams = (origUrlObject, ignoreUrlParametersMatching) => {
876 // Exclude initial '?'
877 const searchString = origUrlObject.search.slice(1);
878
879 // Split into an array of 'key=value' strings
880 const keyValueStrings = searchString.split('&');
881 const keyValuePairs = keyValueStrings.map(keyValueString => {
882 // Split each 'key=value' string into a [key, value] array
883 return keyValueString.split('=');
884 });
885 const filteredKeyValuesPairs = keyValuePairs.filter(keyValuePair => {
886 return ignoreUrlParametersMatching.every(ignoredRegex => {
887 // Return true iff the key doesn't match any of the regexes.
888 return !ignoredRegex.test(keyValuePair[0]);
889 });
890 });
891 const filteredStrings = filteredKeyValuesPairs.map(keyValuePair => {
892 // Join each [key, value] array into a 'key=value' string
893 return keyValuePair.join('=');
894 });
895
896 // Join the array of 'key=value' strings into a string with '&' in
897 // between each
898 const urlClone = new URL(origUrlObject);
899 urlClone.search = filteredStrings.join('&');
900 return urlClone;
901};
902
903/**
904 * This function will take the request URL and manipulate it based on the
905 * configuration options.
906 *
907 * @param {string} url
908 * @param {Object} options
909 * @return {string|null} Returns the URL in the cache that matches the request
910 * if available, other null.
911 *
912 * @private
913 */
914const _getPrecachedUrl = (url, {
915 ignoreUrlParametersMatching = [/^utm_/],
916 directoryIndex = 'index.html',
917 cleanUrls = true,
918 urlManipulation = null
919} = {}) => {
920 const urlObject = new URL(url, location);
921
922 // Change '/some-url#123' => '/some-url'
923 urlObject.hash = '';
924
925 const urlWithoutIgnoredParams = _removeIgnoreUrlParams(urlObject, ignoreUrlParametersMatching);
926
927 let urlsToAttempt = [
928 // Test the URL that was fetched
929 urlObject,
930 // Test the URL without search params
931 urlWithoutIgnoredParams];
932
933 // Test the URL with a directory index
934 if (directoryIndex && urlWithoutIgnoredParams.pathname.endsWith('/')) {
935 const directoryUrl = new URL(urlWithoutIgnoredParams);
936 directoryUrl.pathname += directoryIndex;
937 urlsToAttempt.push(directoryUrl);
938 }
939
940 // Test the URL with a '.html' extension
941 if (cleanUrls) {
942 const cleanUrl = new URL(urlWithoutIgnoredParams);
943 cleanUrl.pathname += '.html';
944 urlsToAttempt.push(cleanUrl);
945 }
946
947 if (urlManipulation) {
948 const additionalUrls = urlManipulation({ url: urlObject });
949 urlsToAttempt = urlsToAttempt.concat(additionalUrls);
950 }
951
952 const cachedUrls = precacheController.getCachedUrls();
953 for (const possibleUrl of urlsToAttempt) {
954 if (cachedUrls.indexOf(possibleUrl.href) !== -1) {
955 // It's a perfect match
956 {
957 logger_mjs.logger.debug(`Precaching found a match for ` + getFriendlyURL_mjs.getFriendlyURL(possibleUrl.toString()));
958 }
959 return possibleUrl.href;
960 }
961 }
962
963 return null;
964};
965
966const moduleExports = {};
967
968/**
969 * Add items to the precache list, removing any duplicates and
970 * store the files in the
971 * ["precache cache"]{@link module:workbox-core.cacheNames} when the service
972 * worker installs.
973 *
974 * This method can be called multiple times.
975 *
976 * Please note: This method **will not** serve any of the cached files for you,
977 * it only precaches files. To respond to a network request you call
978 * [addRoute()]{@link module:workbox-precaching.addRoute}.
979 *
980 * If you have a single array of files to precache, you can just call
981 * [precacheAndRoute()]{@link module:workbox-precaching.precacheAndRoute}.
982 *
983 * @param {Array<Object|string>} entries Array of entries to precache.
984 *
985 * @alias workbox.precaching.precache
986 */
987moduleExports.precache = entries => {
988 precacheController.addToCacheList(entries);
989
990 if (installActivateListenersAdded || entries.length <= 0) {
991 return;
992 }
993
994 installActivateListenersAdded = true;
995 self.addEventListener('install', event => {
996 event.waitUntil(precacheController.install({
997 suppressWarnings,
998 plugins
999 }));
1000 });
1001 self.addEventListener('activate', event => {
1002 event.waitUntil(precacheController.activate({
1003 plugins
1004 }));
1005 });
1006};
1007
1008/**
1009 * Add a `fetch` listener to the service worker that will
1010 * respond to
1011 * [network requests]{@link https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Custom_responses_to_requests}
1012 * with precached assets.
1013 *
1014 * Requests for assets that aren't precached, the `FetchEvent` will not be
1015 * responded to, allowing the event to fall through to other `fetch` event
1016 * listeners.
1017 *
1018 * @param {Object} options
1019 * @param {string} [options.directoryIndex=index.html] The `directoryIndex` will
1020 * check cache entries for a URLs ending with '/' to see if there is a hit when
1021 * appending the `directoryIndex` value.
1022 * @param {Array<RegExp>} [options.ignoreUrlParametersMatching=[/^utm_/]] An
1023 * array of regex's to remove search params when looking for a cache match.
1024 * @param {boolean} [options.cleanUrls=true] The `cleanUrls` option will
1025 * check the cache for the URL with a `.html` added to the end of the end.
1026 * @param {workbox.precaching~urlManipulation} [options.urlManipulation]
1027 * This is a function that should take a URL and return an array of
1028 * alternative URL's that should be checked for precache matches.
1029 *
1030 * @alias workbox.precaching.addRoute
1031 */
1032moduleExports.addRoute = options => {
1033 if (fetchListenersAdded) {
1034 // TODO: Throw error here.
1035 return;
1036 }
1037
1038 fetchListenersAdded = true;
1039 self.addEventListener('fetch', event => {
1040 const precachedUrl = _getPrecachedUrl(event.request.url, options);
1041 if (!precachedUrl) {
1042 {
1043 logger_mjs.logger.debug(`Precaching found no match for ` + getFriendlyURL_mjs.getFriendlyURL(event.request.url));
1044 }
1045 return;
1046 }
1047
1048 let responsePromise = caches.open(cacheName).then(cache => {
1049 return cache.match(precachedUrl);
1050 }).then(cachedResponse => {
1051 if (cachedResponse) {
1052 return cachedResponse;
1053 }
1054
1055 // Fall back to the network if we don't have a cached response (perhaps
1056 // due to manual cache cleanup).
1057 {
1058 logger_mjs.logger.debug(`The precached response for ` + `${getFriendlyURL_mjs.getFriendlyURL(precachedUrl)} in ${cacheName} was not found. ` + `Falling back to the network instead.`);
1059 }
1060
1061 return fetch(precachedUrl);
1062 });
1063
1064 {
1065 responsePromise = responsePromise.then(response => {
1066 // Workbox is going to handle the route.
1067 // print the routing details to the console.
1068 logger_mjs.logger.groupCollapsed(`Precaching is responding to: ` + getFriendlyURL_mjs.getFriendlyURL(event.request.url));
1069 logger_mjs.logger.log(`Serving the precached url: ${precachedUrl}`);
1070
1071 // The Request and Response objects contains a great deal of
1072 // information, hide it under a group in case developers want to see it.
1073 logger_mjs.logger.groupCollapsed(`View request details here.`);
1074 logger_mjs.logger.unprefixed.log(event.request);
1075 logger_mjs.logger.groupEnd();
1076
1077 logger_mjs.logger.groupCollapsed(`View response details here.`);
1078 logger_mjs.logger.unprefixed.log(response);
1079 logger_mjs.logger.groupEnd();
1080
1081 logger_mjs.logger.groupEnd();
1082 return response;
1083 });
1084 }
1085 event.respondWith(responsePromise);
1086 });
1087};
1088
1089/**
1090 * This method will add entries to the precache list and add a route to
1091 * respond to fetch events.
1092 *
1093 * This is a convenience method that will call
1094 * [precache()]{@link module:workbox-precaching.precache} and
1095 * [addRoute()]{@link module:workbox-precaching.addRoute} in a single call.
1096 *
1097 * @param {Array<Object|string>} entries Array of entries to precache.
1098 * @param {Object} options See
1099 * [addRoute() options]{@link module:workbox-precaching.addRoute}.
1100 *
1101 * @alias workbox.precaching.precacheAndRoute
1102 */
1103moduleExports.precacheAndRoute = (entries, options) => {
1104 moduleExports.precache(entries);
1105 moduleExports.addRoute(options);
1106};
1107
1108/**
1109 * Warnings will be logged if any of the precached assets are entered without
1110 * a `revision` property. This is extremely dangerous if the URL's aren't
1111 * revisioned. However, the warnings can be supressed with this method.
1112 *
1113 * @param {boolean} suppress
1114 *
1115 * @alias workbox.precaching.suppressWarnings
1116 */
1117moduleExports.suppressWarnings = suppress => {
1118 suppressWarnings = suppress;
1119};
1120
1121/**
1122 * Add plugins to precaching.
1123 *
1124 * @param {Array<Object>} newPlugins
1125 *
1126 * @alias workbox.precaching.addPlugins
1127 */
1128moduleExports.addPlugins = newPlugins => {
1129 plugins = plugins.concat(newPlugins);
1130};
1131
1132/*
1133 Copyright 2017 Google Inc.
1134
1135 Licensed under the Apache License, Version 2.0 (the "License");
1136 you may not use this file except in compliance with the License.
1137 You may obtain a copy of the License at
1138
1139 https://www.apache.org/licenses/LICENSE-2.0
1140
1141 Unless required by applicable law or agreed to in writing, software
1142 distributed under the License is distributed on an "AS IS" BASIS,
1143 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1144 See the License for the specific language governing permissions and
1145 limitations under the License.
1146*/
1147
1148const finalExport = Object.assign(moduleExports, publicAPI);
1149
1150return finalExport;
1151
1152}(workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private,workbox.core._private));
1153
1154//# sourceMappingURL=workbox-precaching.dev.js.map