Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Velocity EU 2014 — Offline-first web apps

2,923 views

Published on

The upcoming HTML5 feature known as Service Worker is set to turn the web on its head, enabling websites to run without an internet connection and to load quickly even when the connection is bad.

But with that evolutionary step, web applications need to become more complex, and to handle the fact that their source code may remain on a device for much longer than a single session. Without the safety net of starting fresh every time the user hits a link, considerations such as memory management, data consistency, encapsulation and backwards compatibility now come into play. Front-end developers are suddenly fully-fledged software engineers! The web page is our app platform, and the browser our runtime.

The fastest byte is a byte not sent, so the fastest website is the website that doesn’t need to load anything. Step with me into a world of good hacks, unbeatable performance and smart, multivariate responsiveness, drawn from experience building web apps for the FT and The Economist.

Published in: Technology

Velocity EU 2014 — Offline-first web apps

  1. 1. Offline-first web apps Matt Andrews, Financial Times @andrewsmatt, mattandre.ws
  2. 2. • HTML5 • Offline-first • Sideways-swipe-enabled • Add-to-home-screen-able • iOS • Web App
  3. 3. • HTML5 • Offline-first • Sideways-swipe-enabled • Add-to-home-screen-able • iOS • Android • Web App
  4. 4. • HTML5 • Offline-first • Sideways-swipe-enabled • Add-to-home-screen-able • iOS • Android • Windows • Web App
  5. 5. • HTML5 • Offline-first • Sideways-swipe-enabled • Add-to-home-screen-able • iOS • Android • Windows • Firefox • Web App
  6. 6. • HTML5 • Offline-first • Sideways-swipe-enabled • Add-to-home-screen-able • iOS • Android • Windows • Firefox • ALL THE THINGS • Web App
  7. 7. What’s so important about offline?
  8. 8. Internet Connections • Not just on or off • On can sometimes mean off • Slow can be worse than off
  9. 9. So why is FT app so slow?
  10. 10. AppCache CACHE MANIFEST /my-font.ttf /my-styles.css ! ! <DOCTYPE html> <html manifest="mywebapp.manifest">
  11. 11. AppCache CACHE MANIFEST /my-font.ttf /my-styles.css ! NETWORK: * <DOCTYPE html> <html manifest="mywebapp.manifest">
  12. 12. AppCache Hacks • Varying the response of every page based on whether a cookie is set (hack needs to be added to our CDN as well as back end) • Returning an HTTP error on the manifest request when that cookie is not set; • Created an iframe to load a page that loads the manifest rather than referencing it directly. • Without the NETWORK: * hack in your AppCache manifest you will break all non-offline'd resources. • Putting all our API methods on a path starting with /api so that our FALLBACK doesn’t interfere with ajax requests. • Returning different Cache-Control headers on Internet Explorer 10+.
  13. 13. @andrewsmatt
  14. 14. Service Workers + Fetch + Caches
  15. 15. Fetch API XMLHttpRequest revamped
  16. 16. var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState === 4) { if (xhr.status === 200) { alert(xhr.responseText); } else { alert('There was a problem.'); } } }; xhr.ontimeout = function() { alert('There was a problem.'); }; xhr.open('GET', 'http://a.b/c.html'); with XMLHttpRequest
  17. 17. fetch('http://a.b/c.html') .then(function(response) { return response.text(); // can be .json, .blob }) .then(function(text) { alert(text); }) .catch(function() { alert('There was a problem.'); }); with Fetch API
  18. 18. Using Fetch Native within Service Workers only Browser-only polyfill:- github.com/github/fetch ‘Isomorphic’ Fetch Polyfill that works in Node and in the browser via Browserify:- bit.ly/iso-fetch
  19. 19. Cache API Caching that speaks JavaScript
  20. 20. caches.open(‘my-app’) .then(function(cache) { return cache .addAll([ ‘/my-styles.css’, ‘/my-font.ttf’ ]); }); Pre-Cache URLs
  21. 21. caches.match(new Request(‘/my-styles.css’)) .then(function(response) { // got back /my-styles.css }); ‘Fetch’ URLs from Cache
  22. 22. caches.open(‘my-app’) .then(function(cache) { return cache.put(‘/my-fake-endpoint’, new Response(‘Hello!’)); }); Put ‘fake’ responses into the Cache
  23. 23. Put ‘fake’ responses into the Cache WARNING: the difference between ‘add’ & ’put’ is different to the difference between IndexedDB’s ‘add’ & ‘put’ add put IndexedDB INSERT INSERT OR UPDATE Service Worker Caches INSERT OR UPDATE INSERT OR UPDATE
  24. 24. caches.open(‘my-app’) .then(function(cache) { return cache.keys(); }) .then(function(keys) { return cache.addAll(keys); }); Update content in the Cache WARNING: This will ‘break’ any ‘fake requests’ that have been ‘put’ted WARNING: The Service Worker Cache is in addition to the regular HTTP Cache.
  25. 25. Service Workers
  26. 26. <DOCTYPE html> <html> <head><title>mattandre.ws</title></head> <body> <h1>My offline website</h1> <script> navigator.serviceWorker.register(‘./sw.js’) </script> </body> </html>
  27. 27. sw.js:- this.oninstall = function(event) { // prepare website to work offline, // e.g. cache resources }; this.onfetch = function(event) { // listen to, manipulate and/or respond // requests from your app };
  28. 28. sw.js:- this.oninstall = function(event) { var promise = caches.open(‘my-app’) .then(function(cache) { return cache .addAll([ ‘/my-styles.css’, ‘/my-font.ttf’ ]); }); ! event.waitUntil(promise); };
  29. 29. <DOCTYPE html> <html> <head><title>mattandre.ws</title></head> <body> <h1>My offline website</h1> <script> navigator.serviceWorker.register(‘./sw.js’) .then(function() { // installed }) .catch(function() { // didn’t install :( }); </script> </body> </html>
  30. 30. sw.js:- this.onfetch = function(event) { var promise; promise = caches.match(event.request) .catch(function() { return fetch(event.request); }); event.respondWith(promise); };
  31. 31. Service Worker Gotchas
  32. 32. chrome://flags#enable-experimental-web-platform-features
  33. 33. bit.ly/isserviceworkerready
  34. 34. No Caches The Service Worker Cache API does not work yet but a Polyfill exists that uses IndexedDB underneath:- bit.ly/caches-polyfill
  35. 35. Storage Limits • Every origin (protocol+domain+port) gets an allowance of offline storage, typically 50mb • Allowance shared between IndexedDB & Service Workers • Each origin only has access to data in its caches & databases.
  36. 36. Some JavaScript APIs are not available in Service Worker:- • LocalStorage • Synchronous ajax
  37. 37. https
  38. 38. You can use Service Workers to make offline-first websites… …or just to make normal websites faster.
  39. 39. Beyond Service Worker
  40. 40. Advanced Offline • Simple Caches not always enough • Use IndexedDB for more structured data, e.g. user preferences, bookmarks • Don’t use WebSQL it’s deprecated, use the polyfill. bit.ly/idbpolyfill
  41. 41. • Origins can have multiple IndexedDB databases • Each database can have multiple ‘object stores’ (like SQL tables) • An object store must have at least one index – IDB is NoSQL – can only be queried by pre-defined indexes • No free text search
  42. 42. function databaseOpen() {! ! return new Promise(function(resolve, reject) {! ! ! var version = 1;! ! ! var request = indexedDB.open('todos', version);! ! ! request.onupgradeneeded = function(e) {! ! ! ! db = e.target.result;! ! ! ! e.target.transaction.onerror = reject;! ! ! ! db.createObjectStore('todo', {! ! ! ! ! keyPath: '_id'! ! ! ! });! ! ! };! ! ! request.onsuccess = function(e) {! ! ! ! db = e.target.result;! ! ! ! resolve();! ! ! };! ! ! request.onerror = reject;! ! });! } raw javascript
  43. 43. Highly recommend Dexie.org, a Promise-based IndexedDB library
  44. 44. function databaseOpen() {! ! var db = new Dexie('todos');! ! db.version(1).stores({ todo: '_id' });! ! return db.open();! } with Dexie.org
  45. 45. Summary • Service Worker is coming so get ready:- https, Promises, Caches Polyfill … • Use the Fetch API in your applications today bit.ly/iso-fetch / github.com/github/fetch • Want to use IDB? Use dexie.org. Want to support WebSQL? Use the polyfill bit.ly/idbpolyfill. • I’ve written tutorials on how to use all the HTML5 offline tech available for free here:- bit.ly/offline-workshop
  46. 46. Thanks! • Open Source:- github.com/ftlabs FastClick, Polyfill.io, DOM Delegate, Ellipsis, & more • Jobs:- labs.ft.com/jobs • Me:- @andrewsmatt / mattandre.ws

×