|
| 1 | +/* |
| 2 | +Copyright 2015, 2019, 2020 Google LLC. All Rights Reserved. |
| 3 | + Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | + you may not use this file except in compliance with the License. |
| 5 | + You may obtain a copy of the License at |
| 6 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 7 | + Unless required by applicable law or agreed to in writing, software |
| 8 | + distributed under the License is distributed on an "AS IS" BASIS, |
| 9 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 10 | + See the License for the specific language governing permissions and |
| 11 | + limitations under the License. |
| 12 | +*/ |
| 13 | + |
| 14 | +const CACHE_NAME = 'offline'; |
| 15 | + |
| 16 | +// Customize this with a different URL if needed. |
| 17 | +const OFFLINE_URL = 'static/offline.html'; |
| 18 | + |
| 19 | +self.addEventListener('install', event => { |
| 20 | + event.waitUntil( |
| 21 | + (async () => { |
| 22 | + const cache = await caches.open(CACHE_NAME); |
| 23 | + |
| 24 | + |
| 25 | + // Setting {cache: 'reload'} in the new request will ensure that the |
| 26 | + // response isn't fulfilled from the HTTP cache; i.e., it will be from |
| 27 | + // the network. |
| 28 | + await cache.add(new Request(OFFLINE_URL, { cache: 'reload' })); |
| 29 | + })() |
| 30 | + ); |
| 31 | + |
| 32 | + // Force the waiting service worker to become the active service worker. |
| 33 | + self.skipWaiting(); |
| 34 | +}); |
| 35 | + |
| 36 | +self.addEventListener('activate', event => { |
| 37 | + event.waitUntil( |
| 38 | + (async () => { |
| 39 | + // Enable navigation preload if it's supported. |
| 40 | + // See https://developers.google.com/web/updates/2017/02/navigation-preload |
| 41 | + if ('navigationPreload' in self.registration) { |
| 42 | + await self.registration.navigationPreload.enable(); |
| 43 | + } |
| 44 | + })() |
| 45 | + ); |
| 46 | + |
| 47 | + // Tell the active service worker to take control of the page immediately. |
| 48 | + self.clients.claim(); |
| 49 | +}); |
| 50 | + |
| 51 | +self.addEventListener('fetch', event => { |
| 52 | + // We only want to call event.respondWith() if this is a navigation request |
| 53 | + // for an HTML page. |
| 54 | + if (event.request.mode === 'navigate') { |
| 55 | + event.respondWith((async () => { |
| 56 | + try { |
| 57 | + // First, try to use the navigation preload response if it's supported. |
| 58 | + const preloadResponse = await event.preloadResponse; |
| 59 | + |
| 60 | + if (preloadResponse) { |
| 61 | + return preloadResponse; |
| 62 | + } |
| 63 | + |
| 64 | + // Always try the network first. |
| 65 | + const networkResponse = await fetch(event.request); |
| 66 | + |
| 67 | + return networkResponse; |
| 68 | + } catch (error) { |
| 69 | + // catch is only triggered if an exception is thrown, which is likely |
| 70 | + // due to a network error. |
| 71 | + // If fetch() returns a valid HTTP response with a response code in |
| 72 | + // the 4xx or 5xx range, the catch() will NOT be called. |
| 73 | + console.log('Fetch failed; returning offline page instead.', error); |
| 74 | + |
| 75 | + const cache = await caches.open(CACHE_NAME); |
| 76 | + const cachedResponse = await cache.match(OFFLINE_URL); |
| 77 | + |
| 78 | + return cachedResponse; |
| 79 | + } |
| 80 | + })()); |
| 81 | + } |
| 82 | + |
| 83 | + // If our if() condition is false, then this fetch handler won't intercept the |
| 84 | + // request. If there are any other fetch handlers registered, they will get a |
| 85 | + // chance to call event.respondWith(). If no fetch handlers call |
| 86 | + // event.respondWith(), the request will be handled by the browser as if there |
| 87 | + // were no service worker involvement. |
| 88 | +}); |
0 commit comments