1 | this.workbox = this.workbox || {};
|
2 | this.workbox.precaching = (function (DBWrapper_mjs,logger_mjs,cacheNames_mjs,WorkboxError_mjs,fetchWrapper_mjs,cacheWrapper_mjs,assert_mjs,getFriendlyURL_mjs) {
|
3 | ;
|
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
|