Progressive Web Apps: Where Do I Begin?

A presentation at An Event Apart Washington DC in July 2019 in Washington, DC, USA by Aaron Gustafson

Slide 1

Slide 1

PWA s Where Do I Begin? Aaron Gustafson @AaronGustafson noti.st/AaronGustafson

Slide 2

Slide 2

What exactly is a PWA?

Slide 3

Slide 3

What exactly is a Progressive Web App?

Slide 4

Slide 4

What exactly is a Progressive Web App?

Slide 5

Slide 5

What exactly is a Progressive Web App?

Slide 6

Slide 6

What exactly is a Progressive Web App?

Slide 7

Slide 7

“Progressive Progressive Web App” App is a marketing term

Slide 8

Slide 8

Progressive Web App

Slide 9

Slide 9

Game Gallery Book Progressive Web App Newspaper Art Project Tool

Slide 10

Slide 10

Progressive Web Site

Slide 11

Slide 11

Who’s behind PWAs?

Slide 12

Slide 12

@AaronGustafson What’s a PWA, technically? HTTPS

Slide 13

Slide 13

@AaronGustafson What’s a PWA, technically? HTTPS Web App Manifest

Slide 14

Slide 14

@AaronGustafson What’s a manifest? { “lang”: “en”, “short_name”: “Wash Post”, “name”: “The Washington Post”, “icons”: [ { “src”: “img/launcher-icon-2x.png”, “sizes”: “96x96”, “type”: “image/png” } ], “start_url”: “/pwa/”, “display”: “standalone”, “orientation”: “portrait”, “background_color”: “black” }

Slide 15

Slide 15

@AaronGustafson What’s a PWA, technically? HTTPS Web App Manifest Service Worker

Slide 16

Slide 16

Should I believe the hype?

Slide 17

Slide 17

Maybe?

Slide 18

Slide 18

Starbucks: 2x increase in daily active users aka.ms/google-io-2018

Slide 19

Slide 19

Tinder: Core experience with 90% less code aka.ms/tinder-pwa-2017

Slide 20

Slide 20

Trivago: 97% increase in click-outs to hotel offers aka.ms/trivago-pwa-2017

Slide 21

Slide 21

West Elm: 15% increase in time on site 9% increase in revenue per visit aka.ms/west-elm-pwa-2017

Slide 22

Slide 22

Slide 23

Slide 23

@AaronGustafson Let’s talk about Service Worker

Slide 24

Slide 24

@AaronGustafson Registering a Service Worker if ( “serviceWorker” in navigator ) { navigator.serviceWorker.register( “/serviceworker.min.js” ); } h t a P p m is i ! t n a t or

Slide 25

Slide 25

@AaronGustafson The Service Worker Lifecycle Browser Install Activation aka.ms/pwa-lifecycle Ready

Slide 26

Slide 26

@AaronGustafson How connections are made Browser Internet

Slide 27

Slide 27

@AaronGustafson Along comes Service Worker Browser Cache Internet

Slide 28

Slide 28

@AaronGustafson Along comes Service Worker Browser ! Cache Internet

Slide 29

Slide 29

PWAs start with a great web experience and then enhance that experience for performance, resilience, installation, and engagement

Slide 30

Slide 30

Progressive Web App Enhancement

Slide 31

Slide 31

PWAs start with a great web experience and then enhance that experience for performance, resilience, installation, and engagement

Slide 32

Slide 32

Progressive Web App

Slide 33

Slide 33

Progressive /prəˈɡresiv/ happening or developing gradually or in stages; proceeding step by step

Slide 34

Slide 34

Patrick Perkins

Slide 35

Slide 35

Consider forbes.com circa 2007 @AaronGustafson

Slide 36

Slide 36

“Mobile first” thinking isn’t just about mobile

Slide 37

Slide 37

Patrick Perkins

Slide 38

Slide 38

Patrick Perkins

Slide 39

Slide 39

Step 2 Use markup that supports the core experience Avinash Arunachalam AM Patrick Perkins

Slide 40

Slide 40

Avinash Arunachalam A M

Slide 41

Slide 41

@AaronGustafson What does it mean? <div class=”entry”> <div class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</div> <div class=”entry__meta”> <div><b>Published</b> 24 May 2017</div> <div><b>Reading Time</b> 25 minutes</div> </div> <div class=”entry__content”> I had the great pleasure of delivering a talk… <br><br> I do a lot of traveling and it’s… </div> </div>

Slide 42

Slide 42

@AaronGustafson This is self-contained content <div class=”entry”> <div class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</div> <div class=”entry__meta”> <div><b>Published</b> 24 May 2017</div> <div><b>Reading Time</b> 25 minutes</div> </div> <div class=”entry__content”> I had the great pleasure of delivering a talk… <br><br> I do a lot of traveling and it’s… </div> </div>

Slide 43

Slide 43

@AaronGustafson There’s a tag for that: article <article class=”entry”> <div class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</div> <div class=”entry__meta”> <div><b>Published</b> 24 May 2017</div> <div><b>Reading Time</b> 25 minutes</div> </div> <div class=”entry__content”> I had the great pleasure of delivering a talk… <br><br> I do a lot of traveling and it’s… </div> </article>

Slide 44

Slide 44

@AaronGustafson This is the title of the post <article class=”entry”> <div class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</div> <div class=”entry__meta”> <div><b>Published</b> 24 May 2017</div> <div><b>Reading Time</b> 25 minutes</div> </div> <div class=”entry__content”> I had the great pleasure of delivering a talk… <br><br> I do a lot of traveling and it’s… </div> </article>

Slide 45

Slide 45

@AaronGustafson There’s a tag for that: h1-h6 <article class=”entry”> <h1 class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</h1> <div class=”entry__meta”> <div><b>Published</b> 24 May 2017</div> <div><b>Reading Time</b> 25 minutes</div> </div> <div class=”entry__content”> I had the great pleasure of delivering a talk… <br><br> I do a lot of traveling and it’s… </div> </article>

Slide 46

Slide 46

@AaronGustafson Various properties of the post <article class=”entry”> <h1 class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</h1> <div class=”entry__meta”> <div><b>Published</b> 24 May 2017</div> <div><b>Reading Time</b> 25 minutes</div> </div> <div class=”entry__content”> I had the great pleasure of delivering a talk… <br><br> I do a lot of traveling and it’s… </div> </article>

Slide 47

Slide 47

@AaronGustafson There’s an element for that: dl <article class=”entry”> <h1 class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</h1> <dl class=”entry__meta”> <dt>Published</dt> <dd>24 May 2017</dd> <dt>Reading Time</dt> <dd>25 minutes</dd> </dl> <div class=”entry__content”> I had the great pleasure of delivering a talk… <br><br> I do a lot of traveling and it’s… </div> </article>

Slide 48

Slide 48

@AaronGustafson Bonus: time <article class=”entry”> <h1 class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</h1> <dl class=”entry__meta”> <dt>Published</dt> <dd><time>24 May 2017</time></dd> <dt>Reading Time</dt> <dd>25 minutes</dd> </dl> <div class=”entry__content”> I had the great pleasure of delivering a talk… <br><br> I do a lot of traveling and it’s… </div> </article>

Slide 49

Slide 49

@AaronGustafson Bonus: time <time datetime=”2017-05-24”> 24 May 2017</time> <time datetime=”2017-05-24T11:13:24”> 24 May 2017</time> <time datetime=”2017-05-24T11:13:24-04:00”> 24 May 2017</time>

Slide 50

Slide 50

@AaronGustafson “Flow” content with line breaks <article class=”entry”> <h1 class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</h1> <dl class=”entry__meta”> <dt>Published</dt> <dd><time …>24 May 2017</time></dd> <dt>Reading Time</dt> <dd>25 minutes</dd> </dl> <div class=”entry__content”> I had the great pleasure of delivering a talk… <br><br> I do a lot of traveling and it’s… </div> </article>

Slide 51

Slide 51

@AaronGustafson “Flow” content, divided <article class=”entry”> <h1 class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</h1> <dl class=”entry__meta”> <dt>Published</dt> <dd><time …>24 May 2017</time></dd> <dt>Reading Time</dt> <dd>25 minutes</dd> </dl> <div class=”entry__content”> <div>I had the great pleasure of delivering a…</div> <div>I do a lot of traveling and it’s…</div> </div> </article>

Slide 52

Slide 52

@AaronGustafson This is meaningful content <article class=”entry”> <h1 class=”entry__title”>Progressive Web Apps and the Windows Ecosystem</h1> <dl class=”entry__meta”> <dt>Published</dt> <dd><time …>24 May 2017</time></dd> <dt>Reading Time</dt> <dd>25 minutes</dd> </dl> <div class=”entry__content”> <p>I had the great pleasure of delivering a talk…</p> <p>I do a lot of traveling and it’s…</p> </div> </article>

Slide 53

Slide 53

Avinash Arunachalam A M

Slide 54

Slide 54

@AaronGustafson Readability

Slide 55

Slide 55

Slide 56

Slide 56

Hey Cortana, read me the top three headlines in today’s New York Times

Slide 57

Slide 57

@AaronGustafson Access via semantics: function extractHeadlines( response ){ var $html = document.createElement(‘div’), $headings, i=0, headlines=[]; $html.innerHTML = response.contents; $headings = $html.querySelector(‘#top-new’) .querySelectorAll(‘article h1, article h2, article h3’); heading_count = $headings.length; while (headlines.length < 3) { let $link = $headings[i].querySelector(‘a’); if ($link && $link.href) { headlines.push({ title: $headings[i].innerText.trim(), link: $link.href }); } i++; } console.log( headlines ); }

Slide 58

Slide 58

@AaronGustafson Access via semantics: function extractHeadlines( response ){ var $html = document.createElement(‘div’), $headings, i=0, headlines=[]; $html.innerHTML = response.contents; $headings = $html.querySelector(‘#top-new’) .querySelectorAll(‘article h1, article h2, article h3’); heading_count = $headings.length; while (headlines.length < 3) { let $link = $headings[i].querySelector(‘a’); if ($link && $link.href) { headlines.push({ title: $headings[i].innerText.trim(), link: $link.href }); } i++; } console.log( headlines ); }

Slide 59

Slide 59

More about semantics for “headless” UIs aka.ms/conversational-semantics

Slide 60

Slide 60

aka.ms/dependency-awareness

Slide 61

Slide 61

@AaronGustafson Let’s say you needed a button… <input type=”submit” value=”Sign Up”> Sign Up <button type=”submit”>Sign Up</button> <a class=”button” href=”#”>Sign Up</a> <div class=”button”>Sign Up</div>

Slide 62

Slide 62

@AaronGustafson Let’s compare Pattern input[type=submit] button[type=submit] a div Display button Semantics button Focusable? Activate By Submits Forms Yes Mouse, touch, ENTER, SPACE Yes Yes Mouse, touch, ENTER, SPACE Yes No No button button link Named generic Yes Mouse, touch, ENTER block Not exposed No N/A

Slide 63

Slide 63

@AaronGustafson UX gaps that need to be filled Pattern input[type=submit] button[type=submit] a div Display button Semantics button Focusable? Activate By Submits Forms Yes Mouse, touch, ENTER, SPACE Yes Yes Mouse, touch, ENTER, SPACE Yes No No button button link Named generic Yes Mouse, touch, ENTER block Not exposed No N/A

Slide 64

Slide 64

@AaronGustafson Moar dependencies Pattern Display Semantics Focusable? Activate By Submits Forms input[type=submit] None None None None None button[type=submit] None None None None None a CSS ARIA None JavaScript JavaScript div CSS ARIA HTML JavaScript JavaScript

Slide 65

Slide 65

@AaronGustafson Moar dependencies Pattern Display Semantics Focusable? Activate By Submits Forms input[type=submit] None None None None None button[type=submit] None None None None None a CSS ARIA None JavaScript JavaScript div CSS ARIA HTML JavaScript JavaScript

Slide 66

Slide 66

@AaronGustafson Potential for failure Moar dependencies, moar (potential) problems Dependencies

Slide 67

Slide 67

@AaronGustafson Disaster averted

Slide 68

Slide 68

@AaronGustafson Potential for failure Moar dependencies, moar (potential) problems Dependencies

Slide 69

Slide 69

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 70

Slide 70

@AaronGustafson Enhancing UX with markup <input type=”email” name=”email” id=”email” required aria-required=”true”>

Slide 71

Slide 71

@AaronGustafson Enhancing UX with markup <input type=”email” name=”email” id=”email” required aria-required=”true”> Experience deltas 1. Support for email input type? 2. Validation algorithm implemented? 3. Virtual keyboard?

Slide 72

Slide 72

@AaronGustafson Enhancing UX with markup <input type=”email” name=”email” id=”email” required aria-required=”true”> Experience deltas 1. Support for HTML validation?

Slide 73

Slide 73

@AaronGustafson Enhancing UX with markup <input type=”email” name=”email” id=”email” required aria-required=”true”> Experience deltas 1. Browser exposure of aria-required property? 2. Assistive tech implementation of aria-required?

Slide 74

Slide 74

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 75

Slide 75

Avinash Arunachalam A M

Slide 76

Slide 76

Step 3 Design in support of the core experience Avinash Arunachalam AM Chris Grafton

Slide 77

Slide 77

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 78

Slide 78

aka.ms/enhanced-css-layouts

Slide 79

Slide 79

Good design is problem solving. — Jeff Veen

Slide 80

Slide 80

@AaronGustafson Tools for graphic design Alignment Proportion Balance Proximity Contrast Repetition Emphasis Rhythm Gestalt Unity Harmony White Space Movement

Slide 81

Slide 81

@AaronGustafson Tools for graphic design Alignment Proportion Balance Proximity Contrast Repetition Emphasis Rhythm Gestalt Unity Harmony White Space Movement

Slide 82

Slide 82

@AaronGustafson Alignment

Slide 83

Slide 83

@AaronGustafson Contrast

Slide 84

Slide 84

@AaronGustafson Proportion

Slide 85

Slide 85

@AaronGustafson Proximity

Slide 86

Slide 86

@AaronGustafson Rhythm aka.ms/vertical-rhythm

Slide 87

Slide 87

@AaronGustafson Unity

Slide 88

Slide 88

@AaronGustafson Unique design considerations Screen size Resolution Brightness Color density User preference Network speed & quality Assistive technology

Slide 89

Slide 89

@AaronGustafson Unique design considerations Screen size Resolution Brightness Color density User preference Network speed & quality Assistive technology ☞ ☞ ☞ ☞ ☞

Slide 90

Slide 90

@AaronGustafson Unique design considerations Screen size Resolution Brightness Color density User preference Network speed & quality Assistive technology

Slide 91

Slide 91

@AaronGustafson Examples of user preference Larger or smaller fonts @media (min-width: 32em) { … } High contrast colors @media (-ms-high-contrast: active) { … } @media (-ms-high-contrast: white-on-black) { … } @media (-ms-high-contrast: black-on-white) { … } Reduced motion @media (prefers-reduced-motion: reduce) { … }

Slide 92

Slide 92

@AaronGustafson Assistive technologies ๏ Vision ๏ Motor/mobility ๏ Screen magnifiers ๏ Speech recognition ๏ Screen readers ๏ Mouse settings ๏ Braille printers & refreshable braille displays ๏ Keyboards & keyboard overlays ๏ High contrast settings ๏ Eye tracking ๏ Hearing ๏ Captions & subtitles

Slide 93

Slide 93

Don’t rely on color alone to convey important information Confirm Cancel Confirm Cancel

Slide 94

Slide 94

Good contrast ensures your content is readable aka.ms/color-contrast

Slide 95

Slide 95

Explicit connections ensure everyone can follow references

Slide 96

Slide 96

Explicit connections ensure everyone can follow references <a href=”#figure-3-3”>Figure 3.3</a> shows the lodging article in Safari with only the default browser styles applied. …

<figure id=”figure-3-3”> … </figure>

Slide 97

Slide 97

Slide 98

Slide 98

Consider what your design leaves unsaid

Slide 99

Slide 99

Consider what your design leaves unsaid aria-label=”You can finish reading “The Web Should Just Work for Everyone” in less than 10 minutes”

Slide 100

Slide 100

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 101

Slide 101

@AaronGustafson Enhancing design in CSS p { color: green; color: rgba(0, 255, 0, .8); } Passwords can be a hassle. Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 102

Slide 102

@AaronGustafson Enhancing design in CSS p { color: green; color: rgba(0, 255, 0, .8); } Older browsers without RGBa support, ignore the second rule Passwords can be a hassle. Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 103

Slide 103

@AaronGustafson Enhancing design in CSS p { color: green; color: rgba(0, 255, 0, .8); } Modern browsers with RGBa support, overwrite the first rule

Slide 104

Slide 104

@AaronGustafson Enhancing design in CSS h1:has(+ p) { color: green; } (That selects h1s that have adjacent sibling paragraphs.) Passwords can be a hassle Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 105

Slide 105

@AaronGustafson Enhancing design in CSS h1:has(+ p) { color: green; } Browsers that don’t support :has() ignore the entire rule set Passwords can be a hassle Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 106

Slide 106

@AaronGustafson Beware the comma! div:hover .extra-stuff, div:focus-within .extra-stuff { /* reveal it */ }

Slide 107

Slide 107

@AaronGustafson Beware the comma! div:hover .extra-stuff, div:focus-within .extra-stuff { /* reveal it */ } Browsers that don’t support :focus-within

Slide 108

Slide 108

@AaronGustafson Beware the comma! div:hover .extra-stuff, div:focus-within .extra-stuff { /* reveal it */ } Browsers that do support :focus-within

Slide 109

Slide 109

@AaronGustafson Enhancing design in CSS h1:has(+ p) { color: green; } As browsers support :has(), matching h1s will turn green Passwords can be a hassle Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 110

Slide 110

@AaronGustafson Enhancing design in CSS @media only screen { p { color: green; } } Passwords can be a hassle. Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 111

Slide 111

@AaronGustafson Enhancing design in CSS @media only screen { p { color: green; } } Browsers without media query support ignore the block Passwords can be a hassle. Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 112

Slide 112

@AaronGustafson Enhancing design in CSS @media only screen { p { color: green; } } Browsers with media query support apply it Passwords can be a hassle. Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 113

Slide 113

@AaronGustafson Enhancing design in CSS @supports (display: grid) { p { color: green; } } Passwords can be a hassle. Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 114

Slide 114

@AaronGustafson Enhancing design in CSS @supports (display: grid) { p { color: green; } } Browsers that don’t grok @supports ignore the block Passwords can be a hassle. Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 115

Slide 115

@AaronGustafson Enhancing design in CSS @supports (display: grid) { p { color: green; } } Browsers that understand @supports, but don’t support grid ignore it Passwords can be a hassle. Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 116

Slide 116

@AaronGustafson Enhancing design in CSS @supports (display: grid) { p { color: green; } } Browsers that understand @supports and grid apply it Passwords can be a hassle. Most people don’t create strong passwords or make sure to maintain a different one for every site. People create easy-to-remember passwords and typically use the same passwords across all of their accounts.

Slide 117

Slide 117

Chris Grafton

Slide 118

Slide 118

Chris Grafton

Slide 119

Slide 119

aka.ms/enhanced-css-layouts

Slide 120

Slide 120

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 121

Slide 121

“Mobile first” design

Slide 122

Slide 122

“Desktop first”

Slide 123

Slide 123

.primary { float: left; width: 68%; } .secondary { float: right; “Desktop first” width: 32%; }

Slide 124

Slide 124

“Desktop first” @media (max-width:599px) { .primary, .secondary { float: none; width: auto; } }

Slide 125

Slide 125

“Mobile first”

Slide 126

Slide 126

@media (min-width:600px) “Mobile first”

Slide 127

Slide 127

@AaronGustafson Also “mobile first” ๏ Selectively deliver advances styles ๏ Isolate large CSS images in min-width media queries ๏ Don’t hide content images using CSS ๏ Use responsive images ๏ Prefer system fonts ๏ font-display: optional

Slide 128

Slide 128

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 129

Slide 129

Step 4 Improve the core experience with JavaScript ChrisCreswick Grafton Jacob

Slide 130

Slide 130

Jacob Creswick

Slide 131

Slide 131

Jacob Creswick

Slide 132

Slide 132

@AaronGustafson Got let? document.body.innerHTML += ‘<p>Can I count to four?</p>’; for ( let i=1; i<=4; i++ ) { document.body.innerHTML += ‘<p>’ + i + ‘</p>’; } document.body.innerHTML += ‘<p>Success!</p>’;

Slide 133

Slide 133

aka.ms/js-let-down

Slide 134

Slide 134

aka.ms/js-let-down

Slide 135

Slide 135

@AaronGustafson Potential for failure Moar dependencies, moar (potential) problems Dependencies

Slide 136

Slide 136

aka.ms/github-removes-jquery

Slide 137

Slide 137

As part of our refined approach to building frontend features on GitHub.com, we focused on getting away with regular HTML foundation as much as we could, and only adding JavaScript behaviors as progressive enhancement. As a result, even those web forms and other UI elements that were enhanced using JS would usually also work with JavaScript disabled in the browser. aka.ms/github-removes-jquery

Slide 138

Slide 138

As part of our refined approach to building frontend features on GitHub.com, we focused on getting away with regular HTML foundation as much as we could, and only adding JavaScript behaviors as progressive enhancement. As a result, even those web forms and other UI elements that were enhanced using JS would usually also work with JavaScript disabled in the browser. aka.ms/github-removes-jquery

Slide 139

Slide 139

Jacob Creswick

Slide 140

Slide 140

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 141

Slide 141

Slide 142

Slide 142

@AaronGustafson Detecting support if ( navigator.credentials ) { // Actual logic goes here }

Slide 143

Slide 143

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 144

Slide 144

Jacob Creswick

Slide 145

Slide 145

@AaronGustafson Registering a Service Worker if ( navigator.serviceWorker ) { navigator.serviceWorker.register(‘/serviceworker.js’) .then(function(registration) { console.log(‘Success!’, registration.scope); }) .catch(function(error) { console.error(‘Failure!’, error); }); }

Slide 146

Slide 146

@AaronGustafson Object detection FTW! if ( navigator.serviceWorker ) { navigator.serviceWorker.register(‘/serviceworker.js’) .then(function(registration) { console.log(‘Success!’, registration.scope); }) .catch(function(error) { console.error(‘Failure!’, error); }); }

Slide 147

Slide 147

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 148

Slide 148

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 149

Slide 149

@AaronGustafson User Experience Enhance the Service Worker Capabilities

Slide 150

Slide 150

Jacob Creswick

Slide 151

Slide 151

@AaronGustafson User Experience Enhance the experience Capabilities

Slide 152

Slide 152

PWAs start with a great web experience and then enhance that experience for performance, resilience, installation, and engagement

Slide 153

Slide 153

PWAs start with a great web experience and then enhance that experience for performance, resilience, installation, and engagement

Slide 154

Slide 154

Focus Markup Design JavaScript

Slide 155

Slide 155

Thank you! @AaronGustafson aaron-gustafson.com noti.st/AaronGustafson