Slide 1

Slide 1 text

At Your Service The Next Generation of Offline Websites Erik Runyon @erunyon #AIM2 2016.highedweb.org

Slide 2

Slide 2 text

Erik Runyon Technical Director Marketing Communications The University of Notre Dame @erunyon ErikRunyon.com

Slide 3

Slide 3 text

@erunyon #AIM2

Slide 4

Slide 4 text

for all links… ErikRunyon.com

Slide 5

Slide 5 text

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

Welcome to the wonderful world of Service Workers

Slide 8

Slide 8 text

What it is… Service workers act as proxy servers between web applications, the browser, and network. They enable the creation of offline experiences by intercepting network requests and taking appropriate action based on whether the network is available and updated assets reside on the server. https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API

Slide 9

Slide 9 text

http://alistapart.com/article/application-cache-is-a-douchebag

Slide 10

Slide 10 text

… a replacement for Appcache

Slide 11

Slide 11 text

Chrome Android (Chrome) Firefox Opera Safari/iOS Edge IE 40+ 46+ 44+ 27+ None* None** None Current Support * Under Consideration ** In Development http://caniuse.com/#feat=serviceworkers = 61% = 55% = 55% Global U.S.A. Notre Dame

Slide 12

Slide 12 text

WebKit 5-year plan “People think they want it, some of them actually do want it. We should probably do it.” https://trac.webkit.org/wiki/FiveYearPlanFall2015

Slide 13

Slide 13 text

https://webkit.org/status/#specification-service-workers

Slide 14

Slide 14 text

Is ServiceWorker ready? https://jakearchibald.github.io/isserviceworkerready/

Slide 15

Slide 15 text

A Service Worker is a stand-alone javascript file that is initialized from elsewhere in the site and has control over its current scope.

Slide 16

Slide 16 text

Makes extensive use of Promises https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

Slide 17

Slide 17 text

SW Can’t access the DOM directly https://developer.mozilla.org/en-US/docs/Web/API/Client/postMessage

Slide 18

Slide 18 text

Browsers that support Service Workers also support ECMAScript6 (ES2015)

Slide 19

Slide 19 text

Why Service Workers?

Slide 20

Slide 20 text

Speed!!!!

Slide 21

Slide 21 text

Network Unavailable

Slide 22

Slide 22 text

Hunny-Do https://github.com/erunyon/hunny-do

Slide 23

Slide 23 text

How Service Workers work

Slide 24

Slide 24 text

Without SW

Slide 25

Slide 25 text

Without SW

Slide 26

Slide 26 text

service-worker.js With SW cache

Slide 27

Slide 27 text

service-worker.js With SW cache

Slide 28

Slide 28 text

Why require HTTPS?

Slide 29

Slide 29 text

HTTP/2

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

http://webpolicy.org/2015/08/25/att-hotspots-now-with-advertising-injection/

Slide 32

Slide 32 text

https://letsencrypt.org/

Slide 33

Slide 33 text

HigherEd 13% redirect to https https://erikrunyon.com/highered-rwd-directory/

Slide 34

Slide 34 text

Service Worker Lifecycle

Slide 35

Slide 35 text

// site.js function loadImage(){ var rand = (Math.floor(Math.random() * 200) + 200); var img = document.createElement("img"); img.src = 'https://placekitten.com/' + rand + '/300'; document.getElementById('images').appendChild(img); } https://demos.erikrunyon.com/sw-img-override/

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

1. Register // site.js if('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); } https://demos.erikrunyon.com/sw-img-override/

Slide 38

Slide 38 text

2. Installing // sw.js self.addEventListener('install', event => { self.skipWaiting(); }); https://demos.erikrunyon.com/sw-img-override/

Slide 39

Slide 39 text

3. Activating self.addEventListener('activate', event => { self.clients.claim(); }); https://davidwalsh.name/service-worker-claim

Slide 40

Slide 40 text

4. Start intercepting requests! self.addEventListener('fetch', event => { let request = event.request; if(request.headers.get('Accept').indexOf('text/html') !== -1){ event.respondWith( fetch(request) ); return; } if(request.headers.get('Accept').indexOf('image') !== -1){ let rand = (Math.floor(Math.random() * 200) + 200); event.respondWith( fetch( 'https://www.placecage.com/' + rand + ‘/300', {mode: 'no-cors'} ) ); } }); https://demos.erikrunyon.com/sw-img-override/

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

'use strict'; self.addEventListener('install', event => { self.skipWaiting(); }); self.addEventListener('activate', event => { self.clients.claim(); }); self.addEventListener('fetch', event => { let request = event.request; if(request.headers.get('Accept').indexOf('text/html') !== -1){ event.respondWith( fetch(request) ); return; } if(request.headers.get('Accept').indexOf('image') !== -1){ let rand = (Math.floor(Math.random() * 200) + 200); event.respondWith( fetch( 'https://www.placecage.com/' + rand + ‘/300', {mode: 'no-cors'} ) ); } });

Slide 43

Slide 43 text

Brooklyn Bridge - New York Cleaning up

Slide 44

Slide 44 text

@DeanoHume Dynamic Responsive Image Using WebP Images http://deanhume.com/home/blogpost/service-workers--dynamic-responsive-images-using-webp-images/10132

Slide 45

Slide 45 text

Offline

Slide 46

Slide 46 text

A Popular Workflow 1. Store theme, important pages, and offline page in cache 2. Cache additional pages and images as the user browses 3. On repeat visit, theme files default to the cache 4. Pages default to the network 5. Account for missing pages and images while offline https://erikrunyon.com/sw.js

Slide 47

Slide 47 text

1. Register // site.js if('serviceWorker' in navigator) { navigator.serviceWorker.register('/sw.js'); }

Slide 48

Slide 48 text

2. Installing self.addEventListener('install', function(event) { event.waitUntil( caches.open(my_cache_version).then(function(cache) { return cache.addAll([ '/css/images/leaves-right.jpg', '/css/images/icons-social.png', '/css/site.css', '/js/site.js', '/', '/offline/' ]); }).then( () => self.skipWaiting() ) ); }); https://erikrunyon.com/sw.js

Slide 49

Slide 49 text

3. Activating self.addEventListener('activate', event => { event.waitUntil( caches.keys() .then( keys => { return Promise.all(keys .filter(key => key.indexOf(my_cache_version) !== 0) .map(key => caches.delete(key)) ); }); ).then( () => self.clients.claim() ); }); https://erikrunyon.com/sw.js

Slide 50

Slide 50 text

4. Start intercepting requests! // Images (return SVG when offline) if (request.headers.get('Accept').indexOf('image') !== -1) { return new Response('', {headers: {'Content-Type': 'image/svg+xml'}} ); } // HTML if (request.headers.get('Accept').indexOf('text/html') !== -1) { // Do something } https://erikrunyon.com/sw.js

Slide 51

Slide 51 text

Offline Forms

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

Misc

Slide 54

Slide 54 text

Terminated when not in use, and restarted when it's next needed (can’t persist variables).

Slide 55

Slide 55 text

Dynamically Update Cache Version https://erikrunyon.com/2016/03/service-worker-version-using-jekyll/ 'use strict'; const version = ‘{{ site.time | date: ‘%Y%m%d%H%M%S' }}::'; const staticCacheName = version + 'static'; const pagesCacheName = version + 'pages'; const imagesCacheName = version + 'images';

Slide 56

Slide 56 text

Send data to a Service Worker using PostMessage // In the site javascript file window.addEventListener('load', function () { if(navigator.serviceWorker.controller) { navigator.serviceWorker.controller.postMessage({ 'myRandomStuff': { width:document.body.clientWidth, height:document.body.clientHeight } }); } }); // In the Service Worker self.addEventListener('message', event => { console.log(event.data.myRandomStuff); }); https://developer.mozilla.org/en-US/docs/Web/API/Client/postMessage

Slide 57

Slide 57 text

Service Workers in the Wild • lyza.com* • adactio.com* • ponyfoo.com* • smashingmagazine.com* • medium.com • modernizr.com • serviceworke.rs • theguardian.com • platform-status.mozilla.org chrome://serviceworker-internals/

Slide 58

Slide 58 text

What else will Service Workers do? 1. Handling push notifications 2. Background data synchronization 3. Responding to resource requests from other origins 4. Entering a geo-fence 5. Reacting to a particular time & date https://w3c.github.io/ServiceWorker/

Slide 59

Slide 59 text

https://serviceworke.rs/ ServiceWorker Cookbook

Slide 60

Slide 60 text

Working with Service Workers

Slide 61

Slide 61 text

Chrome Dev Tools

Slide 62

Slide 62 text

Chrome Dev Tools

Slide 63

Slide 63 text

chrome://serviceworker-internals/

Slide 64

Slide 64 text

Progressive Web Apps

Slide 65

Slide 65 text

Progressive Web Applications take advantage of new technologies to bring the best of mobile sites and native applications to users. They're reliable, fast, and engaging. https://developers.google.com/web/progressive-web-apps/ “

Slide 66

Slide 66 text

Web App Manifest https://w3c.github.io/manifest/ This specification defines a JSON-based manifest file that provides developers with a centralized place to put metadata associated with a web application. This metadata includes, but is not limited to, the web application's name, links to icons, as well as the preferred URL to open when a user launches the web application.

Slide 67

Slide 67 text

Installable Web Apps • is associated with a manifest with at least a name member and a suitable icon. • is served over a secure network connection. • has a sensible content security policy. • is able to responsibly adapt to display on a variety of screen sizes, catering for both mobile and desktop. • is able to function without a network connection. • is repeatedly used by the end-user over some extended period of time. • has been explicitly marked by the user as one that they value and trust (e.g., by bookmarking or "starring" it). https://w3c.github.io/manifest/

Slide 68

Slide 68 text

Google’s pre-reqs • Must have a web app manifest file • The manifest must have a `short_name`, a name for display in the banner • A start URL (e.g. / or index.html) which must be loadable • At least an `144x144` PNG icon • Icon declarations should include a mime type of image/png • Should have a service worker registered on the site • Served over HTTPS (service worker requires HTTPS for security) • The user has visited your site at least twice, with at least five minutes between visits https://developers.google.com/web/updates/2015/03/increasing-engagement-with-app-install-banners-in-chrome-for-android

Slide 69

Slide 69 text

manifest.json

Slide 70

Slide 70 text

• fullscreen: take over the whole screen. • standalone: opens the app with a status bar. • minimal-ui: like on iOS, the app is fullscreen, but certain actions can cause the navigation bar and back/forward buttons to reappear. • browser: opens your app with normal browser toolbars and buttons. “display” options

Slide 71

Slide 71 text

No content

Slide 72

Slide 72 text

No content

Slide 73

Slide 73 text

https://www.nd.edu/?sw=true

Slide 74

Slide 74 text

PWA Resources

Slide 75

Slide 75 text

https://codelabs.developers.google.com/codelabs/your-first-pwapp/ Your First Progressive Web App

Slide 76

Slide 76 text

http://bit.ly/chrome-server Web Server for Chrome

Slide 77

Slide 77 text

http://bit.ly/google-lighthouse Lighthouse

Slide 78

Slide 78 text

https://github.com/GoogleChrome/ Google Chrome on GitHub

Slide 79

Slide 79 text

https://www.smashingmagazine.com/serviceWorker.js Smashing Magazine

Slide 80

Slide 80 text

Wrapping Up

Slide 81

Slide 81 text

Find a reason to play with new web technology.

Slide 82

Slide 82 text

Erik Runyon erikrunyon.com @erunyon thank you Credits Offline phone graphic: @tpacket Hunny-Do Design: @zastrow Browser logos: https://github.com/alrra/browser-logos Photos: Lego worker: https://www.flickr.com/photos/stavos52093/ Postage Stamp Show: https://www.flickr.com/photos/vegaskent/3265121626/ Terminator: Dan Shearn - http://mungolovescandy.blogspot.com/