writing offline first web applications in the future
slides.forbesl.co.uk
CACHE MANIFEST
# updated 2013-06-18T14:51:58.057Z
/
/static/2.0.0/style.css
/static/2.0.0/background.png
/static/2.0.0/image.png
Must be SSL
<script>
navigator.serviceWorker.register("/assets/v1/worker.js").then(
function(serviceWorker) {
console.log("success!");
// To use the serviceWorker immediately,
// you might call location.reload()
}, function(error) {
console.error("Installing the worker failed!:", error);
});
</script>
// hosted at: /assets/v1/worker.js
this.version = 1;
var base = 'https://videos.example.com';
var inventory = base + '/services/inventory/data.json';
this.addEventListener('install', function(e) {
});
this.addEventListener('fetch', function(e) {
var url = e.request.url;
console.log(url);
if (url == inventory) {
e.respondWith(new Response({
statusCode: 200,
body: JSON.stringify({/* ... */})
}));
}
});
this.addEventListener('install', function(e) {
// Create a cache of resources.
// Begins the process of fetching them.
var shellResources = new Cache(
base + "/assets/v1/base.css",
base + "/assets/v1/app.js",
base + "/assets/v1/logo.png",
base + "/assets/v1/intro_video.webm",
);
// The coast is only clear when all the resources are ready.
e.waitUntil(shellResources.ready());
// Add Cache to the global so it can be used later during onfetch
caches.set("shell-v1", shellResources);
});
this.addEventListener('fetch', function(e) {
// All operations on caches are async, including matching URLs,
// so we use Promises heavily.
e.respondWith(fetch(e.request).catch(function() {
return caches.match(e.request);
}));
});
var updatedFromFresh = false;
showSpinner();
var cacheUpdate = fetchData({useCache:true}).then(function (data) {
if (!updatedFromFresh) {
updatePage(data);
}
});
var freshUpdate = fetchData({useCache:false}).then(function (data) {
updatePage(data);
updatedFromFresh = true;
});
cacheUpdate.catch(function () {
return freshUpdate;
}).catch(showNoDataError).then(hideSpinner);
function fetchData(options) {
var xhr = new XMLHttpRequest();
xhr.open('get', 'http://api.example.com/gallery.json');
if (opts.useCache) {
if (!navigator.serviceWorker) {
return Promise.reject(new Error('No worker'));
}
xhr.setRequestHeader('x-use-cache', 'true');
}
// `sendAsPromised` doesn't really exist yet
return xhr.sendAsPromised();
}
this.addEventListener('fetch', function(e) {
var useCache = e.request.headers.has('x-use-cache');
e.request.headers.delete('x-use-cache');
if (useCache) {
e.respondWith(caches.match(e.request));
} else {
e.respondWith(fetch(e.request));
caches.get('api').update(e.request);
}
});
slides.forbesl.co.uk
Twitter: @ForbesLindesay
GitHub: @ForbesLindesay
Blog: www.forbeslindesay.co.uk
Jade
Browserify Middleware
readable-email.org
brcdn.org
tempjs.org