service-worker.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. /**
  2. * Copyright 2016 Google Inc. All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. // DO NOT EDIT THIS GENERATED OUTPUT DIRECTLY!
  17. // This file should be overwritten as part of your build process.
  18. // If you need to extend the behavior of the generated service worker, the best approach is to write
  19. // additional code and include it using the importScripts option:
  20. // https://github.com/GoogleChrome/sw-precache#importscripts-arraystring
  21. //
  22. // Alternatively, it's possible to make changes to the underlying template file and then use that as the
  23. // new base for generating output, via the templateFilePath option:
  24. // https://github.com/GoogleChrome/sw-precache#templatefilepath-string
  25. //
  26. // If you go that route, make sure that whenever you update your sw-precache dependency, you reconcile any
  27. // changes made to this original template file with your modified copy.
  28. // This generated service worker JavaScript will precache your site's resources.
  29. // The code needs to be saved in a .js file at the top-level of your site, and registered
  30. // from your pages in order to be used. See
  31. // https://github.com/googlechrome/sw-precache/blob/master/demo/app/js/service-worker-registration.js
  32. // for an example of how you can register this script and handle various service worker events.
  33. /* eslint-env worker, serviceworker */
  34. /* eslint-disable indent, no-unused-vars, no-multiple-empty-lines, max-nested-callbacks, space-before-function-paren, quotes, comma-spacing */
  35. 'use strict';
  36. var precacheConfig = [["404.html","64c7057a5dcac7a561798f6f87b412ff"],["browserconfig.xml","67c3113b1574fecc6015d56d774e1d38"],["categories/index.xml","1c183b48cab635f689386c900b9dc4aa"],["css/fonts/miriamlibre-bold.woff","96496f6f06535d25b3bcba876917ca35"],["css/fonts/miriamlibre-bold.woff2","668defa44d9a74dd709ce0c826a5eb11"],["css/images/arrow_effect.svg","1434d178461f70c16b77acb4bdbc51e3"],["css/images/icon-tick.svg","35d4d4728ea80d254508b2bca4109d70"],["css/images/stripe.svg","fa3f32a026b6a1bb04ee98d963432e15"],["css/prism.css","004029c8c70ed2bbaa5d9debcf14f8c7"],["css/styles.css","4a9f58ade51a0d0093a6380aed62ca44"],["images/android-icon-144x144.png","43e1f47f182b13d0dee15f510213e928"],["images/android-icon-192x192.png","4c07782e52e0ab714074e6d3d69dc3ec"],["images/android-icon-36x36.png","3b2cd8c925a66bf84c89b68bb30e5f62"],["images/android-icon-48x48.png","45dc386eea1d8a46216a8b6de9b156c6"],["images/android-icon-512x512.png","42d6b28cc7eb41810a5392c81368340a"],["images/android-icon-72x72.png","b04c64637efed2b04fa900ddfcbfe75d"],["images/android-icon-96x96.png","bd9c126a4d6baf7ce442122ce0e89e11"],["images/apple-icon-precomposed.png","478755b1c3e0d2c8aea975033cff9ac8"],["images/apple-icon.png","478755b1c3e0d2c8aea975033cff9ac8"],["images/apple-touch-icon-114x114.png","95804b2192b0cea406b54cb31345c47d"],["images/apple-touch-icon-120x120.png","b5da0625c9e876bdf9768875f7dd9cca"],["images/apple-touch-icon-144x144.png","976151c9ecd72311dc6024917292209d"],["images/apple-touch-icon-152x152.png","8bd6a2e592c1c8463b5205ba8436227e"],["images/apple-touch-icon-180x180.png","56a93f4271dea903196794095e9f9ccc"],["images/apple-touch-icon-57x57.png","977183ab3bfb98da8d79e025f1cb4946"],["images/apple-touch-icon-60x60.png","55e9e05103a9b472a52f4c572a73b2b2"],["images/apple-touch-icon-72x72.png","1ef87a2887baab846f2501beb27445ee"],["images/apple-touch-icon-76x76.png","769826cd7526df4db7f4ba1a820158bd"],["images/bad_design_system.png","9c0e87a34e7d842b0e2831dc947249aa"],["images/browser-chrome-android.svg","3100b2a9c5f0e34982c717fc2aa46d73"],["images/browser-chrome.svg","fa39b4be6727525330e928f582fbe80a"],["images/browser-edge.svg","9e8265ab8f6a701587a4271dd3aa6a73"],["images/browser-firefox-android.svg","452df7b9e83c70a07e8e03b4e8dab9c4"],["images/browser-firefox.svg","d3093eda664be3d0cc6d791e1386420f"],["images/browser-ie.svg","13e192cf2b3fe17e7049a49b7d085caa"],["images/browser-opera.svg","95d65630c9f7deef6a3098af8f5baf9f"],["images/browser-safari-ios.svg","f729e629ec998ec40d313495d7257741"],["images/browser-safari.svg","523ee9491f5a937b8975f4d23aa77f62"],["images/favicon-16x16.png","7a99c20d6c00babddd26d03607b8721d"],["images/favicon-32x32.png","129881474a1bf130027bff7a1e89febd"],["images/favicon-96x96.png","bd9c126a4d6baf7ce442122ce0e89e11"],["images/favicon.ico","81c46feedbfcc6c6dc9495e4fd5adfad"],["images/icon-info.svg","53a6c555ce41f818556c71ab0dfc533b"],["images/icon-tag.svg","f067bbbc072941b2a0335679300bfc6c"],["images/icon-warning.svg","2a4322abbee9aed694fadb50e98a1f61"],["images/logo.svg","50293a256b796b9a737f1969d511a98e"],["images/ms-icon-144x144.png","43e1f47f182b13d0dee15f510213e928"],["images/ms-icon-150x150.png","e73370837ab9060772a18d62aaacd0f0"],["images/ms-icon-310x310.png","8a7143516b929702e3309bb537a99c5c"],["images/ms-icon-70x70.png","d7c6e7368733d53b5f979546d5aa4fe9"],["images/open_in_desktop.png","e899d6679b011aa7b0e783683d90d99b"],["images/samsung_homescreen.png","5ef40e64a18f966ce5c9084a024256db"],["images/serve_from_docs.png","15ae9eac3737a21593ebe00a9312bf9e"],["index.html","ed6f299f3ada8884cde3d1aa8f087999"],["index.xml","57693b1a4b4d3df29fb5fd5fb2165f91"],["js/dom-scripts.js","d1226c17a56c156113ee538031a0b6bf"],["js/prism.js","0c1fb8d3a69ee7c91dbf0f361ded7763"],["js/service-worker-registration.js","d60f01dc1393cbaaf4f7435339074d5e"],["manifest.json","47399fd703e572a010a718a351c37b03"],["patterns/coding/code-blocks/index.html","eb8b4a5608ad58842f11397ea6738e46"],["patterns/coding/color-palettes/index.html","dbd0b5ec8d5c920a5b3e6a9d16dfe4ea"],["patterns/coding/command-line/index.html","08a2bede6d49ed0c0966c7251f025349"],["patterns/coding/demo-embedding/index.html","edb617ff5677a855240b29e78e7cfe12"],["patterns/coding/file-trees/index.html","2018ee28e6741dd2b039c96a9cb1cf6f"],["patterns/coding/index.html","fa95d165746f7006400f5a6289a24bca"],["patterns/coding/index.xml","003debc3b6c2568d0118de3cbc1aaaf9"],["patterns/coding/tested/index.html","885fad18412f4fb6b93bc3d5f9245c5f"],["patterns/coding/writing-inline-demos/index.html","1b8d660c3599b9445a2170ba39aec7ec"],["patterns/index.html","3088821ec9ee3424fe0ce7826e8b663d"],["patterns/index.xml","276f7358cc6c122ee8b38ec4f86f116f"],["patterns/installation/index.html","4b5b97dba40cb1131b22536e0f40c526"],["patterns/media/including-images/index.html","5501f1b162de829ebba408fe93e2e871"],["patterns/media/including-videos/index.html","68c1b03ce92b5d78be46b312670ab49f"],["patterns/media/index.html","c2e39c5f91dbf5ae238b53881ded734a"],["patterns/media/index.xml","69e133cec08e19eeb33cb005e90590e3"],["patterns/printing/index.html","21cbb13255f6606783e35781d05b3cd0"],["patterns/serving/index.html","74bcbf568897a307e7d156c2679cd8b5"],["patterns/setup/index.html","f64759b069335c7e868c50505756f161"],["patterns/updating/index.html","e6f19a2d952417a9ffa353489f13f1c7"],["patterns/writing/expandable-sections/index.html","56dff4c7ee6bc6cc75805da0471fd67f"],["patterns/writing/index.html","6b876040b71134ead191ec7ea8b222dc"],["patterns/writing/index.xml","53aea727e5ea1133e83cd6a859115e7e"],["patterns/writing/markdown-and-metadata/index.html","2f8a7b540428740bcf3c6f76fe575eb7"],["patterns/writing/notes-and-warnings/index.html","f4d3ae3e5cf35b67b2834b04c0e5a305"],["patterns/writing/project-structure/index.html","6582a714b06c27a5f11fce7675b740e8"],["patterns/writing/references/index.html","944274c1a4c028fa868e658726ea3fd6"],["patterns/writing/snippets/index.html","defd3b88e44cef79a0ad246aab417cad"],["patterns/writing/tables-of-contents/index.html","2aef3ef8756d51908cd971115e076513"],["print-version/index.html","5673939f81869ba153d1d05952028b37"],["sitemap.xml","e3f27a45b9955c8ee5f7f72517c65417"],["tags/index.xml","7445f2e8ccc722d44e7533263233d2df"],["tags/markdown/index.html","d6d084b6803ba11bfff11a789689859a"],["tags/markdown/index.xml","5387a8d0317e6b6641e0803ac2f5af3c"],["tags/metadata/index.html","e8c8ede1b409776b684986065f8ef511"],["tags/metadata/index.xml","098f151053be1a17654318a88433154b"]];
  37. var cacheName = 'sw-precache-v3-sw-precache-' + (self.registration ? self.registration.scope : '');
  38. var ignoreUrlParametersMatching = [/^utm_/];
  39. var addDirectoryIndex = function (originalUrl, index) {
  40. var url = new URL(originalUrl);
  41. if (url.pathname.slice(-1) === '/') {
  42. url.pathname += index;
  43. }
  44. return url.toString();
  45. };
  46. var cleanResponse = function (originalResponse) {
  47. // If this is not a redirected response, then we don't have to do anything.
  48. if (!originalResponse.redirected) {
  49. return Promise.resolve(originalResponse);
  50. }
  51. // Firefox 50 and below doesn't support the Response.body stream, so we may
  52. // need to read the entire body to memory as a Blob.
  53. var bodyPromise = 'body' in originalResponse ?
  54. Promise.resolve(originalResponse.body) :
  55. originalResponse.blob();
  56. return bodyPromise.then(function(body) {
  57. // new Response() is happy when passed either a stream or a Blob.
  58. return new Response(body, {
  59. headers: originalResponse.headers,
  60. status: originalResponse.status,
  61. statusText: originalResponse.statusText
  62. });
  63. });
  64. };
  65. var createCacheKey = function (originalUrl, paramName, paramValue,
  66. dontCacheBustUrlsMatching) {
  67. // Create a new URL object to avoid modifying originalUrl.
  68. var url = new URL(originalUrl);
  69. // If dontCacheBustUrlsMatching is not set, or if we don't have a match,
  70. // then add in the extra cache-busting URL parameter.
  71. if (!dontCacheBustUrlsMatching ||
  72. !(url.pathname.match(dontCacheBustUrlsMatching))) {
  73. url.search += (url.search ? '&' : '') +
  74. encodeURIComponent(paramName) + '=' + encodeURIComponent(paramValue);
  75. }
  76. return url.toString();
  77. };
  78. var isPathWhitelisted = function (whitelist, absoluteUrlString) {
  79. // If the whitelist is empty, then consider all URLs to be whitelisted.
  80. if (whitelist.length === 0) {
  81. return true;
  82. }
  83. // Otherwise compare each path regex to the path of the URL passed in.
  84. var path = (new URL(absoluteUrlString)).pathname;
  85. return whitelist.some(function(whitelistedPathRegex) {
  86. return path.match(whitelistedPathRegex);
  87. });
  88. };
  89. var stripIgnoredUrlParameters = function (originalUrl,
  90. ignoreUrlParametersMatching) {
  91. var url = new URL(originalUrl);
  92. // Remove the hash; see https://github.com/GoogleChrome/sw-precache/issues/290
  93. url.hash = '';
  94. url.search = url.search.slice(1) // Exclude initial '?'
  95. .split('&') // Split into an array of 'key=value' strings
  96. .map(function(kv) {
  97. return kv.split('='); // Split each 'key=value' string into a [key, value] array
  98. })
  99. .filter(function(kv) {
  100. return ignoreUrlParametersMatching.every(function(ignoredRegex) {
  101. return !ignoredRegex.test(kv[0]); // Return true iff the key doesn't match any of the regexes.
  102. });
  103. })
  104. .map(function(kv) {
  105. return kv.join('='); // Join each [key, value] array into a 'key=value' string
  106. })
  107. .join('&'); // Join the array of 'key=value' strings into a string with '&' in between each
  108. return url.toString();
  109. };
  110. var hashParamName = '_sw-precache';
  111. var urlsToCacheKeys = new Map(
  112. precacheConfig.map(function(item) {
  113. var relativeUrl = item[0];
  114. var hash = item[1];
  115. var absoluteUrl = new URL(relativeUrl, self.location);
  116. var cacheKey = createCacheKey(absoluteUrl, hashParamName, hash, false);
  117. return [absoluteUrl.toString(), cacheKey];
  118. })
  119. );
  120. function setOfCachedUrls(cache) {
  121. return cache.keys().then(function(requests) {
  122. return requests.map(function(request) {
  123. return request.url;
  124. });
  125. }).then(function(urls) {
  126. return new Set(urls);
  127. });
  128. }
  129. self.addEventListener('install', function(event) {
  130. event.waitUntil(
  131. caches.open(cacheName).then(function(cache) {
  132. return setOfCachedUrls(cache).then(function(cachedUrls) {
  133. return Promise.all(
  134. Array.from(urlsToCacheKeys.values()).map(function(cacheKey) {
  135. // If we don't have a key matching url in the cache already, add it.
  136. if (!cachedUrls.has(cacheKey)) {
  137. var request = new Request(cacheKey, {credentials: 'same-origin'});
  138. return fetch(request).then(function(response) {
  139. // Bail out of installation unless we get back a 200 OK for
  140. // every request.
  141. if (!response.ok) {
  142. throw new Error('Request for ' + cacheKey + ' returned a ' +
  143. 'response with status ' + response.status);
  144. }
  145. return cleanResponse(response).then(function(responseToCache) {
  146. return cache.put(cacheKey, responseToCache);
  147. });
  148. });
  149. }
  150. })
  151. );
  152. });
  153. }).then(function() {
  154. // Force the SW to transition from installing -> active state
  155. return self.skipWaiting();
  156. })
  157. );
  158. });
  159. self.addEventListener('activate', function(event) {
  160. var setOfExpectedUrls = new Set(urlsToCacheKeys.values());
  161. event.waitUntil(
  162. caches.open(cacheName).then(function(cache) {
  163. return cache.keys().then(function(existingRequests) {
  164. return Promise.all(
  165. existingRequests.map(function(existingRequest) {
  166. if (!setOfExpectedUrls.has(existingRequest.url)) {
  167. return cache.delete(existingRequest);
  168. }
  169. })
  170. );
  171. });
  172. }).then(function() {
  173. return self.clients.claim();
  174. })
  175. );
  176. });
  177. self.addEventListener('fetch', function(event) {
  178. if (event.request.method === 'GET') {
  179. // Should we call event.respondWith() inside this fetch event handler?
  180. // This needs to be determined synchronously, which will give other fetch
  181. // handlers a chance to handle the request if need be.
  182. var shouldRespond;
  183. // First, remove all the ignored parameters and hash fragment, and see if we
  184. // have that URL in our cache. If so, great! shouldRespond will be true.
  185. var url = stripIgnoredUrlParameters(event.request.url, ignoreUrlParametersMatching);
  186. shouldRespond = urlsToCacheKeys.has(url);
  187. // If shouldRespond is false, check again, this time with 'index.html'
  188. // (or whatever the directoryIndex option is set to) at the end.
  189. var directoryIndex = 'index.html';
  190. if (!shouldRespond && directoryIndex) {
  191. url = addDirectoryIndex(url, directoryIndex);
  192. shouldRespond = urlsToCacheKeys.has(url);
  193. }
  194. // If shouldRespond is still false, check to see if this is a navigation
  195. // request, and if so, whether the URL matches navigateFallbackWhitelist.
  196. var navigateFallback = '';
  197. if (!shouldRespond &&
  198. navigateFallback &&
  199. (event.request.mode === 'navigate') &&
  200. isPathWhitelisted([], event.request.url)) {
  201. url = new URL(navigateFallback, self.location).toString();
  202. shouldRespond = urlsToCacheKeys.has(url);
  203. }
  204. // If shouldRespond was set to true at any point, then call
  205. // event.respondWith(), using the appropriate cache key.
  206. if (shouldRespond) {
  207. event.respondWith(
  208. caches.open(cacheName).then(function(cache) {
  209. return cache.match(urlsToCacheKeys.get(url)).then(function(response) {
  210. if (response) {
  211. return response;
  212. }
  213. throw Error('The cached response that was expected is missing.');
  214. });
  215. }).catch(function(e) {
  216. // Fall back to just fetch()ing the request if some unexpected error
  217. // prevented the cached response from being valid.
  218. console.warn('Couldn\'t serve response for "%s" from cache: %O', event.request.url, e);
  219. return fetch(event.request);
  220. })
  221. );
  222. }
  223. }
  224. });