Slide 1

Slide 1 text

The UnCloud

Slide 2

Slide 2 text

Basically UNCLOUD?

Slide 3

Slide 3 text

Once upon a time… 1980s

Slide 4

Slide 4 text

…fast forward 2010s

Slide 5

Slide 5 text

Something happened 1980s 2010s

Slide 6

Slide 6 text

TL;DR: 2007

Slide 7

Slide 7 text

@cedmax Front end
 developer since able to grow a beard. 90s/00s

Slide 8

Slide 8 text

Basically postAPPSERA

Slide 9

Slide 9 text

Challenges Privacy Security Design & Ux Context APIs access …

Slide 10

Slide 10 text

The web? 2004

Slide 11

Slide 11 text

The web…

Slide 12

Slide 12 text

…was different

Slide 13

Slide 13 text

Adapt 2008/9

Slide 14

Slide 14 text

Adapt 2008/9

Slide 15

Slide 15 text

“The landscape is shifting, perhaps more quickly than we might like.” 
 Ethan Marcotte
 http://alistapart.com/article/responsive-web-design 2010

Slide 16

Slide 16 text

Flexibility 2008/9

Slide 17

Slide 17 text

Catch up

Slide 18

Slide 18 text

“Mobile browsing is expected to outpace desktop-based access within three to five years.” 
 Ethan Marcotte
 http://alistapart.com/article/responsive-web-design

Slide 19

Slide 19 text

Challenges Privacy Security Design & Ux Context APIs access …

Slide 20

Slide 20 text

Network perception

Slide 21

Slide 21 text

Internet

Slide 22

Slide 22 text

“I intend to protect a free and open Internet, extend its reach to every classroom, and every community, and help folks build the fastest network.” 
 Barack Obama, President of USA
 https://www.whitehouse.gov/blog/2015/01/20/watch-president-obamas-2015-state-union

Slide 23

Slide 23 text

offline is a big deal

Slide 24

Slide 24 text

Application Cache 2010

Slide 25

Slide 25 text

# offline.appcache CACHE MANIFEST assets/v6/script/script.min.js assets/v6/style/main.min.css assets/v6/style/font/pro.ttf assets/v6/style/img/sprites.png

Slide 26

Slide 26 text

No content

Slide 27

Slide 27 text

Biggest 
 problem Cache First Only
 &
 The Cache only updates if 
 the manifest itself changes

Slide 28

Slide 28 text

Slide 29

Slide 29 text

“We all know someone who needs “observing” more than others in case they do something really stupid. ApplicationCache is one of those people” 
 Jake Archibald
 http://alistapart.com/article/application-cache-is-a-douchebag 2012

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

Basically current state

Slide 32

Slide 32 text

you might have heard of

Slide 33

Slide 33 text

“A service worker is a script that is run by your browser in the background, separate from a web page, opening the door to features which don’t need a web page or user interaction.” 
 Matt Gaunt
 http://www.html5rocks.com/en/tutorials/service-worker/introduction/

Slide 34

Slide 34 text

Pretty powerful

Slide 35

Slide 35 text

but with great powers…

Slide 36

Slide 36 text

Can’t access the DOM Can’t hold a state[1] It’s event driven 
 can access IndexDB API [1] serviceworker.js

Slide 37

Slide 37 text

No content

Slide 38

Slide 38 text

self.addEventListener('install', function(event) { //[…] }); self.addEventListener('activate', function(event) { //[…] }); self.addEventListener('fetch', function(event) { //[…] });

Slide 39

Slide 39 text

a working example

Slide 40

Slide 40 text

// script.js if (navigator.serviceWorker) { navigator.serviceWorker.register('/serviceworker.js'); }

Slide 41

Slide 41 text

// serviceworker.js var staticCacheName = 'cache-v1'; var urlsToCache = [ '/', '/styles/main.css', '/script/main.js', '/offline' ]; function updateStaticCache() { return caches.open(staticCacheName) .then(function(cache) { return cache.addAll(urlsToCache); }); }; self.addEventListener('install', function (event) { event.waitUntil(updateStaticCache()); });

Slide 42

Slide 42 text

// serviceworker.js var staticCacheName = 'cache-v1'; var urlsToCache = [ '/', '/styles/main.css', '/script/main.js', '/offline' ]; function updateStaticCache() { return caches.open(staticCacheName) .then(function(cache) { return cache.addAll(urlsToCache); }); }; self.addEventListener('install', function (event) { event.waitUntil(updateStaticCache()); });

Slide 43

Slide 43 text

// serviceworker.js var staticCacheName = 'cache-v1'; var urlsToCache = [ '/', '/styles/main.css', '/script/main.js', '/offline' ]; function updateStaticCache() { return caches.open(staticCacheName) .then(function(cache) { return cache.addAll(urlsToCache); }); }; self.addEventListener('install', function (event) { event.waitUntil(updateStaticCache()); });

Slide 44

Slide 44 text

// serviceworker.js var staticCacheName = 'cache-v1'; var urlsToCache = [ '/', '/styles/main.css', '/script/main.js', '/offline' ]; function updateStaticCache() { return caches.open(staticCacheName) .then(function(cache) { return cache.addAll(urlsToCache); }); }; self.addEventListener('install', function (event) { event.waitUntil(updateStaticCache()); });

Slide 45

Slide 45 text

// serviceworker.js var staticCacheName = 'cache-v1'; var urlsToCache = [ '/', '/styles/main.css', '/script/main.js', '/offline' ]; function updateStaticCache() { return caches.open(staticCacheName) .then(function(cache) { return cache.addAll(urlsToCache); }); }; self.addEventListener('install', function (event) { event.waitUntil(updateStaticCache()); });

Slide 46

Slide 46 text

“When the user navigates to your site, the browser tries to redownload the script file that defined the service worker in the background.” 
 Matt Gaunt
 http://www.html5rocks.com/en/tutorials/service-worker/introduction/

Slide 47

Slide 47 text

// serviceworker.js var staticCacheName = ‘cache-v2'; var clearOldCaches = function() { return caches.keys().then(function(keys) { return Promise.all( keys.filter(function (key) { return key.indexOf(version) != 0; }).map(function (key) { return caches.delete(key); }) ); }) } self.addEventListener("activate", function(event) { event.waitUntil(clearOldCaches()) });

Slide 48

Slide 48 text

// serviceworker.js var staticCacheName = ‘cache-v2'; var clearOldCaches = function() { return caches.keys().then(function(keys) { return Promise.all( keys.filter(function (key) { return key.indexOf(version) != 0; }).map(function (key) { return caches.delete(key); }) ); }) } self.addEventListener("activate", function(event) { event.waitUntil(clearOldCaches()) });

Slide 49

Slide 49 text

// serviceworker.js var staticCacheName = ‘cache-v2'; var clearOldCaches = function() { return caches.keys().then(function(keys) { return Promise.all( keys.filter(function (key) { return key.indexOf(version) != 0; }).map(function (key) { return caches.delete(key); }) ); }) } self.addEventListener("activate", function(event) { event.waitUntil(clearOldCaches()) });

Slide 50

Slide 50 text

// serviceworker.js self.addEventListener('fetch', function(event) { //Where the magic lives });

Slide 51

Slide 51 text

cache first

Slide 52

Slide 52 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( caches.match(request) .then(function (response) { return response || fetch(request) .catch(handleFailure) }) ); });

Slide 53

Slide 53 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( caches.match(request) .then(function (response) { return response || fetch(request) .catch(handleFailure) }) ); });

Slide 54

Slide 54 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( caches.match(request) .then(function (response) { return response || fetch(request) .catch(handleFailure) }) ); });

Slide 55

Slide 55 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( caches.match(request) .then(function (response) { return response || fetch(request) .catch(handleFailure) }) ); });

Slide 56

Slide 56 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( caches.match(request) .then(function (response) { return response || fetch(request) .catch(handleFailure) }) ); });

Slide 57

Slide 57 text

network first

Slide 58

Slide 58 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( fetch(request, { credentials: 'include' }) .catch(function () { return caches.match(request) .then(function (response) { return response || caches.match('/offline'); }) }) ); });

Slide 59

Slide 59 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( fetch(request, { credentials: 'include' }) .catch(function () { return caches.match(request) .then(function (response) { return response || caches.match('/offline'); }) }) ); });

Slide 60

Slide 60 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( fetch(request, { credentials: 'include' }) .catch(function () { return caches.match(request) .then(function (response) { return response || caches.match('/offline'); }) }) ); });

Slide 61

Slide 61 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( fetch(request, { credentials: 'include' }) .catch(function () { return caches.match(request) .then(function (response) { return response || caches.match('/offline'); }) }) ); });

Slide 62

Slide 62 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( fetch(request, { credentials: 'include' }) .catch(function () { return caches.match(request) .then(function (response) { return response || caches.match('/offline'); }) }) ); });

Slide 63

Slide 63 text

// serviceworker.js self.addEventListener('fetch', function(event) { event.respondWith( fetch(request, { credentials: 'include' }) .catch(function () { return caches.match(request) .then(function (response) { return response || caches.match('/offline'); }) }) ); });

Slide 64

Slide 64 text

not a GET?

Slide 65

Slide 65 text

// serviceworker.js self.addEventListener('fetch', function(event) { var request = event.request; if (request.method !== 'GET') { event.respondWith( fetch(request) .catch(function () { return caches.match('/offline'); }) ); return; } });

Slide 66

Slide 66 text

// serviceworker.js self.addEventListener('fetch', function(event) { var request = event.request; if (request.method !== 'GET') { event.respondWith( fetch(request) .catch(function () { return caches.match('/offline'); }) ); return; } });

Slide 67

Slide 67 text

// serviceworker.js self.addEventListener('fetch', function(event) { var request = event.request; if (request.method !== 'GET') { event.respondWith( fetch(request) .catch(function () { return caches.match('/offline'); }) ); return; } });

Slide 68

Slide 68 text

// serviceworker.js self.addEventListener('fetch', function(event) { var request = event.request; if (request.method !== 'GET') { event.respondWith( fetch(request) .catch(function () { return caches.match('/offline'); }) ); return; } });

Slide 69

Slide 69 text

wrapping up

Slide 70

Slide 70 text

// serviceworker.js function isHMTL(request){ return request.headers.get('Accept') .indexOf('text/html') !== -1; } self.addEventListener('fetch', function(event) { var request = event.request; if (request.method !== 'GET') { return networkOnly(event); } if (isHTML(request)) { return networkFirst(event); } else { return cacheFirst(event); } });

Slide 71

Slide 71 text

// serviceworker.js function isHMTL(request){ return request.headers.get('Accept') .indexOf('text/html') !== -1; } self.addEventListener('fetch', function(event) { var request = event.request; if (request.method !== 'GET') { return networkOnly(event); } if (isHTML(request)) { return networkFirst(event); } else { return cacheFirst(event); } });

Slide 72

Slide 72 text

// serviceworker.js function isHMTL(request){ return request.headers.get('Accept') .indexOf('text/html') !== -1; } self.addEventListener('fetch', function(event) { var request = event.request; if (request.method !== 'GET') { return networkOnly(event); } if (isHTML(request)) { return networkFirst(event); } else { return cacheFirst(event); } });

Slide 73

Slide 73 text

// serviceworker.js function isHMTL(request){ return request.headers.get('Accept') .indexOf('text/html') !== -1; } self.addEventListener('fetch', function(event) { var request = event.request; if (request.method !== 'GET') { return networkOnly(event); } if (isHTML(request)) { return networkFirst(event); } else { return cacheFirst(event); } });

Slide 74

Slide 74 text

service workers give you control

Slide 75

Slide 75 text

https://serviceworke.rs/ The Service Worker Cookbook is a collection of working, practical examples of using service workers in modern web apps.

Slide 76

Slide 76 text

Basically WHAT NOW?

Slide 77

Slide 77 text

demo time https://pokedex.org 2015/16

Slide 78

Slide 78 text

this is sorted

Slide 79

Slide 79 text

but is it?

Slide 80

Slide 80 text

// script.js if (navigator.serviceWorker) { navigator.serviceWorker.register('/serviceworker.js'); }

Slide 81

Slide 81 text

Progressive enhancement

Slide 82

Slide 82 text

We’ll fix that

Slide 83

Slide 83 text

a takeaway note

Slide 84

Slide 84 text

Does this make any sense?

Slide 85

Slide 85 text

“ There will always be some alternative that is technologically more advanced than the web. First there were CD- ROMs. Then we had Flash. Now we have native apps.” 
 Jeremy Keith
 https://adactio.com/journal/9016

Slide 86

Slide 86 text

And yet the web persists.

Slide 87

Slide 87 text

Responsive Web Design Ethan Marcotte 
 http://alistapart.com/article/responsive-web-design Application Cache is A Douchebag Jake Archibald http://alistapart.com/article/application-cache-is-a- douchebag Introduction to Service Worker
 Matt Gaunt http://www.html5rocks.com/en/tutorials/service- worker/introduction/ Pokedex.org Nolan Lawson https://pokedex.org https://github.com/nolanlawson/pokedex.org My First Service Worker Jeremy Keith https://adactio.com/journal/9775 Web! What is it good for? Jeremy Keith https://adactio.com/journal/9016 Resources [email protected] http://cedmax.com @cedmax any question?