-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
* Basic service worker sample revamp. * Review feedback.
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
Basic Service Worker Sample | ||
=========================== | ||
See https://googlechrome.github.io/samples/service-worker/basic/index.html for a live demo. | ||
|
||
Learn more at https://www.chromestatus.com/feature/6561526227927040 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
if ('serviceWorker' in navigator) { | ||
navigator.serviceWorker.register('service-worker.js'); | ||
} | ||
|
||
document.querySelector('#show').addEventListener('click', () => { | ||
const iconUrl = document.querySelector('select').selectedOptions[0].value; | ||
let imgElement = document.createElement('img'); | ||
imgElement.src = iconUrl; | ||
document.querySelector('#container').appendChild(imgElement); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,49 +1,100 @@ | ||
<!DOCTYPE html> | ||
<!-- | ||
Copyright 2014 Google Inc. All Rights Reserved. | ||
--- | ||
feature_name: Basic Service Worker | ||
chrome_version: 40 | ||
feature_id: 6561526227927040 | ||
local_css_files: ['styles.css'] | ||
--- | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
<h3>Background</h3> | ||
<p> | ||
This sample demonstrates a basic service worker that could be used as-is, or | ||
as a starting point for further customization. | ||
</p> | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
--> | ||
<script> | ||
var scope = 'hello/'; | ||
var registration; | ||
|
||
function register() { | ||
navigator.serviceWorker.register('service-worker.js', {scope: scope}) | ||
.then(function(r) { | ||
console.log('registered: '); | ||
registration = r; | ||
console.log(registration); | ||
}) | ||
.catch(function(whut) { | ||
console.error('uh oh... '); | ||
console.error(whut); | ||
}); | ||
} | ||
|
||
function unregister() { | ||
registration.unregister() | ||
.then(function() { | ||
console.log('unregistered'); | ||
}); | ||
} | ||
</script> | ||
<button onclick="register()">Register</button> | ||
<button onclick="unregister()">Unregister</button> | ||
|
||
<p>Some nice places to visit: | ||
<h4>What It Does</h4> | ||
<ul> | ||
<li> | ||
Precaches the HTML, JavaScript, and CSS files needed to display this page offline. | ||
(Try it out by reloading the page without a network connection!) | ||
</li> | ||
<li>Cleans up the previously precached entries when the cache name is updated.</li> | ||
<li>Intercepts network requests, returning a cached response when available.</li> | ||
<li> | ||
If there's no cached response, fetches the response from the network and | ||
adds it to the cache for future use. | ||
</li> | ||
</ul> | ||
<p> | ||
You can confirm the service worker's behavior using the | ||
<a href="https://developers.google.com/web/tools/chrome-devtools/debug/progressive-web-apps/">Application panel</a> | ||
of Chrome's DevTools. | ||
</p> | ||
|
||
<h4>What It Doesn't Do</h4> | ||
<ul> | ||
<li><a href="hello/world">world</a> | ||
<li><a href="hello/Cleveland">Cleveland</a> | ||
<li> | ||
Automatically version any of the precached resources.<br> | ||
<em> | ||
You must manually update the <code>CACHES.PRECACHE</code> name to pick up | ||
new versions after updating anything! | ||
</em> | ||
</li> | ||
<li> | ||
Cache-bust the precaching requests.<br> | ||
<em> | ||
The <code>cache.addAll()</code> call may be fulfilled with responses from | ||
the HTTP cache, depending on the HTTP caching headers you use. If you | ||
are using | ||
<a href="https://jakearchibald.com/2016/caching-best-practices/">HTTP caching</a> | ||
and unversioned resources, it can be safer to | ||
<a href="https://github.com/GoogleChrome/samples/blob/5c20f8d74d890fad3d867747d2c3fc853727700c/service-worker/prefetch/service-worker.js#L56">cache-bust</a> | ||
your precaching requests. | ||
</em> | ||
</li> | ||
<li> | ||
Refresh the entries in the runtime cache.<br> | ||
<em> | ||
Once an entry is added to the runtime cache, it's used indefinitely, | ||
without consulting the network to check for updates. If your runtime cache | ||
is used for resources that might be updated, a different strategy, like | ||
<a href="https://jakearchibald.com/2014/offline-cookbook/#stale-while-revalidate">stale-while-revalidate</a> | ||
could be more appropriate. | ||
</em> | ||
</li> | ||
<li> | ||
Clean out the runtime cache.<br> | ||
<em> | ||
The runtime cache will grow as new resource URLs are requested. In this | ||
example, there are only 5 different images that might be loaded, so the | ||
cache size isn't a concern. If your web app might request an arbitrary | ||
number of unique resource URLs, then using a library like | ||
<a href="https://github.com/GoogleChrome/sw-toolbox"><code>sw-toolbox</code></a> | ||
which provides | ||
<a href="https://github.com/GoogleChrome/sw-toolbox/tree/master/recipes/cache-expiration-options">cache-expiration</a> | ||
is recommended. | ||
</em> | ||
</li> | ||
</ul> | ||
|
||
<h3>Live Demo</h3> | ||
<p> | ||
The following demo illustrates the service worker's runtime caching by loading | ||
images in response to clicking the button below. | ||
</p> | ||
<p> | ||
The first time a given image is requested, the service worker will be load it | ||
from the network, but each subsequent time, it will be retrieved from the cache. | ||
</p> | ||
<label for="icons">Icons:</label> | ||
<select id="icons"> | ||
<option value="icons/ic_create_new_folder_black_48dp.png">New Folder</option> | ||
<option value="icons/ic_file_upload_black_48dp.png">File Upload</option> | ||
<option value="icons/ic_folder_black_48dp.png">Closed Folder</option> | ||
<option value="icons/ic_folder_open_black_48dp.png">Open Folder</option> | ||
<option value="icons/ic_folder_shared_black_48dp.png">Shared Folder</option> | ||
</select> | ||
<button id="show">Show Icon</button> | ||
<div id="container"></div> | ||
|
||
{% include js_snippet.html filename='demo.js' %} | ||
{% include js_snippet.html filename='service-worker.js' displayonly=true title="Service Worker's JavaScript" %} |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,76 @@ | ||
self.addEventListener('fetch', function(event) { | ||
console.log('got a request'); | ||
/* | ||
Copyright 2016 Google Inc. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
var salutation = 'Hello, '; | ||
var whom = decodeURIComponent(event.request.url.match(/\/([^/]*)$/)[1]); | ||
var energyLevel = (whom === 'Cleveland') ? '!!!' : '!'; | ||
var version = '\n\n(Version 1)'; | ||
// Names of the two caches used in this version of the service worker. | ||
// Change to v2, etc. when you update any of the local resources, which will | ||
// in turn trigger the install event again. | ||
const PRECACHE = 'precache-v1'; | ||
const RUNTIME = 'runtime'; | ||
|
||
var body = new Blob([salutation, whom, energyLevel, version]); | ||
// A list of local resources we always want to be cached. | ||
const PRECACHE_URLS = [ | ||
'index.html', | ||
'./', // Alias for index.html | ||
'styles.css', | ||
'../../styles/main.css', | ||
'demo.js' | ||
]; | ||
|
||
event.respondWith(new Response(body)); | ||
// The install handler takes care of precaching the resources we always need. | ||
self.addEventListener('install', event => { | ||
event.waitUntil( | ||
caches.open(PRECACHE) | ||
.then(cache => cache.addAll(PRECACHE_URLS)) | ||
.then(self.skipWaiting()) | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
jakearchibald
|
||
); | ||
}); | ||
|
||
// The activate handler takes care of cleaning up old caches. | ||
self.addEventListener('activate', event => { | ||
const currentCaches = [PRECACHE, RUNTIME]; | ||
event.waitUntil( | ||
caches.keys().then(cacheNames => { | ||
return cacheNames.filter(cacheName => !currentCaches.includes(cacheName)); | ||
}).then(cachesToDelete => { | ||
return Promise.all(cachesToDelete.map(cacheToDelete => { | ||
return caches.delete(cacheToDelete); | ||
})); | ||
}).then(() => self.clients.claim()) | ||
); | ||
}); | ||
|
||
// The fetch handler serves responses for same-origin resources from a cache. | ||
// If no response is found, it populates the runtime cache with the response | ||
// from the network before returning it to the page. | ||
self.addEventListener('fetch', event => { | ||
// Skip cross-origin requests, like those for Google Analytics. | ||
if (event.request.url.startsWith(self.location.origin)) { | ||
event.respondWith( | ||
caches.match(event.request).then(cachedResponse => { | ||
if (cachedResponse) { | ||
return cachedResponse; | ||
} | ||
|
||
return caches.open(RUNTIME).then(cache => { | ||
return fetch(event.request).then(response => { | ||
// Put a copy of the response in the runtime cache. | ||
return cache.put(event.request, response.clone()).then(() => { | ||
return response; | ||
}); | ||
}); | ||
}); | ||
}) | ||
); | ||
} | ||
}); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
#container { | ||
display: flex; | ||
flex-direction: row; | ||
flex-wrap: wrap; | ||
justify-content: space-around; | ||
} | ||
|
||
li { | ||
margin-bottom: 1em; | ||
} |
Of all my problems with service workers, I have the most problems with getting a new SW to finish the installing phase and move on to activation. And this line is very curious.
Over in sw-precache you
then()
to a function that returnsskipWaiting()
: sw-precache/service-worker.tmpl And we see that in mozilla's examples too.Whereas here, the skipWaiting is evaluated "immediately", which I suppose races with the cache opening, right? I can't tell if that's intentional. But I do see the same thing in tests in chromium.
Then flipkart actually uses TWO calls on
e.waitUntil
which the spec is fairly unclear about:And lastly I see this pattern from @jakearchibald from the other day, which immediately calls
skipWaiting
(not withine.waitUntil
), but afterwards populates the cacheSo I'm hoping to figure out:
skipWaiting
race against cache population during the install handler?skipWaiting
'ing after population is done?e.waitUntil
legit?