1const cacheVersion = 'grow-1.1.1'; 2 3self.addEventListener('install', function (evt) { 4 skipWaiting(); 5 evt.waitUntil(precache()); 6}); 7 8self.addEventListener('fetch', function (evt) { 9 const request = evt.request; 10 11 // Ignore requests for back office-related URLs 12 if (request.url.includes('/umbraco')) { 13 return; 14 } 15 if (request.url.includes('/sb')) { 16 return; 17 } 18 if (request.url.includes('/App_Plugins')) { 19 return; 20 } 21 22 // Ignore non-GET requests 23 if (request.method !== 'GET') { 24 return; 25 } 26 27 // Ignore all requests to Google Analytics 28 if (request.url.search('google-analytics.com') != -1) { 29 return; 30 } 31 32 // Block chrome extension scripts 33 if (request.url.search('extension:') != -1) { 34 return; 35 } 36 37 // Ignore video requests because of Safari's range bug 38 // https://philna.sh/blog/2018/10/23/service-workers-beware-safaris-range-request/ 39 if (request.url.match(/\.(mp4)$/)) { 40 return; 41 } 42 43 evt.respondWith(fromCache(request)); 44}); 45 46function precache() { 47 // Delete old caches 48 caches.keys().then(function (names) { 49 [].forEach.call(names, function (name) { 50 if (name != cacheVersion) { 51 caches.delete(name); 52 } 53 }); 54 }); 55 56 // Cache homepage 57 return caches.open(cacheVersion).then(function (cache) { 58 // Cache everything 59 return cache.addAll([ 60 '/' 61 ]); 62 }); 63} 64 65function fromCache(request) { 66 // Network first: for pages 67 if (request.destination == 'document') { 68 return fetch(request).then(function (response) { 69 let responseClone = response.clone(); 70 71 caches.open(cacheVersion).then(function (cache) { 72 cache.put(request, responseClone); 73 }); 74 75 return response; 76 }).catch(function () { 77 return caches.open(cacheVersion).then(function (cache) { 78 return cache.match(request).then(function (matching) { 79 if (matching) { 80 return matching; 81 } 82 }); 83 }); 84 }); 85 } 86 87 // Cache first: For everything else 88 return caches.open(cacheVersion).then(function (cache) { 89 return cache.match(request).then(function (matching) { 90 if (matching) { 91 return matching; 92 } else { 93 // Update cache if online 94 return fetch(request).then(function (response) { 95 let responseClone = response.clone(); 96 caches.open(cacheVersion).then(function (cache) { 97 cache.put(request, responseClone); 98 }); 99 return response; 100 }); 101 } 102 }).catch(function () { 103 // Serve offline asset if not online 104 if (request.url.match(/\.(jpe?g|png|gif|svg)$/)) { 105 return missingImage(request); 106 } 107 return; 108 }); 109 }); 110} 111 112function missingImage(request) { 113 if (navigator.onLine === false) { 114 return new Response(` 115 <svg role="img" aria-labelledby="offline-title" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid slice"> 116 <title id="offline-title">Offline</title> 117 <g fill="none" fill-rule="evenodd"> 118 <path fill="#000e29" d="M0 0h400v300H0z"/> 119 <text fill="#878787" font-family="Helvetica Neue,Arial,Helvetica,sans-serif" font-size="72" font-weight="normal"> 120 <tspan x="93" y="172">offline</tspan> 121 </text> 122 </g> 123 </svg>`, 124 { 125 headers: { 126 'Content-Type': 'image/svg+xml', 127 'Cache-Control': 'no-store' 128 } 129 } 130 ); 131 } else { 132 return fetch(request).then(function (response) { 133 return response; 134 }); 135 } 136}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.