Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Blink and you’ll miss it: Building a progressive web app with HTTP/2

Blink and you’ll miss it: Building a progressive web app with HTTP/2

This talk was first presented at Fluent Conference San Jose on the 21st June 2017.

https://conferences.oreilly.com/fluent/fl-ca/public/schedule/detail/58114

Presentation Details
----------------------------------
Imagine a world where you can access content on the web regardless of network connection in the blink of an eye. Progressive web apps are a total game changer for the web, enabling developers to build lightning-fast, engaging experiences. Drawing on firsthand experience at Settled, Dean Hume shares a step-by-step guide to implementing this technology in your own projects.

Settled set out to build a new dashboard for its customers using progressive web apps and HTTP/2. The company wanted to build an offline-first application that allowed users to quickly and easily access their information on the go regardless of their network connection. When the application was implemented, Settled noticed an immediate change: its users spent twice as long on the site, they consumed 15x less data, and enjoyed a 3x faster load times. Dean walks you through Settled’s journey, sharing lessons learned along the way and practical tips that you can use when building your own web apps.

Topics include:

- Using HTTP/2 and the challenges and benefits that it brings
- The steps Settled took when building an offline-first progressive web app
- Bulletproof service worker caching
- Building for sub-500 millisecond page-load times
- Eliminating third-party single points of failure
- Debugging challenges

Dean Hume

June 21, 2017
Tweet

More Decks by Dean Hume

Other Decks in Programming

Transcript

  1. Blink and you’ll miss it
    Building a Progressive Web App with HTTP/2

    View Slide

  2. Dean Hume
    @deanohume

    View Slide

  3. I work for a
    company
    called Settled

    View Slide

  4. View Slide

  5. Instead
    ➔ Transparent
    ➔ Online
    ➔ Everything to help
    you get “Settled” into
    your new home

    View Slide

  6. Our
    Customers
    56%

    View Slide

  7. ● Is accessible on any device
    We needed an experience that:

    View Slide

  8. ● Is accessible on any device
    ● Is fast
    We needed an experience that:

    View Slide

  9. ● Is accessible on any device
    ● Is fast
    ● Works with little or no internet
    connection
    We needed an experience that:

    View Slide

  10. ● Is accessible on any device
    ● Is fast
    ● Works with little or no internet
    connection
    ● Uses one codebase
    We needed an experience that:

    View Slide

  11. ● Is accessible on any device
    ● Is fast
    ● Works with little or no internet
    connection
    ● Uses one codebase
    ● Has an “app-like” feel
    We needed an experience that:

    View Slide

  12. Progressive Web Apps

    View Slide

  13. This is our journey

    View Slide

  14. This talk
    1. Basics of progressive web apps

    View Slide

  15. This talk
    1. Basics of progressive web apps
    2. Fast

    View Slide

  16. This talk
    1. Basics of progressive web apps
    2. Fast
    3. Reliable

    View Slide

  17. This talk
    1. Basics of progressive web apps
    2. Fast
    3. Reliable
    4. Look and feel

    View Slide

  18. The basics
    of
    Progressive Web Apps

    View Slide

  19. These apps aren’t packaged and
    deployed through stores, they’re
    just websites that took all the right
    vitamins.
    Alex Russell - Google

    View Slide

  20. Building blocks
    Website

    View Slide

  21. Building blocks
    Website Service
    Worker

    View Slide

  22. Building blocks
    Website Service
    Worker
    Manifest
    File

    View Slide

  23. Building blocks
    Website HTTPS
    Service
    Worker
    Manifest
    File

    View Slide

  24. Think of your web apps requests
    as planes taking off.
    ServiceWorker is the air traffic
    controller that routes the
    requests.
    Jeff Posnick - Google

    View Slide

  25. Behind the scenes

    View Slide

  26. With Service Workers

    View Slide

  27. With Service Workers

    View Slide

  28. With Service Workers

    View Slide

  29. With Service Workers

    View Slide

  30. Service Workers are
    the key to unlocking
    the power

    View Slide

  31. The perfect
    progressive
    enhancement.

    View Slide

  32. HTTPS Only

    View Slide

  33. Free SSL

    View Slide

  34. Support

    View Slide

  35. You are already using them

    View Slide

  36. 2. Fast

    View Slide

  37. Caching

    View Slide

  38. Caching
    HTTP/2

    View Slide

  39. Caching
    HTTP/2
    Techniques

    View Slide

  40. Caching

    View Slide

  41. With Service Workers

    View Slide

  42. With Service Workers

    View Slide

  43. First Visit

    View Slide

  44. View Slide

  45. View Slide

  46. Register

    View Slide

  47. Register Install

    View Slide

  48. Register Install Activate

    View Slide

  49. Caching
    const cacheName = 'pageCache';

    View Slide

  50. Caching
    const cacheName = 'pageCache';
    this.addEventListener('install', event => {
    event.waitUntil(caches.open(cacheName)
    .then(function(cache) { }));
    });

    View Slide

  51. Caching
    const cacheName = 'pageCache';
    this.addEventListener('install', event => {
    event.waitUntil(caches.open(cacheName)
    .then(function(cache) { return cache.addAll(['result.min.css', './js/material.min.js']); }));
    });

    View Slide

  52. Caching
    const cacheName = 'pageCache';
    this.addEventListener('install', event => {
    event.waitUntil(caches.open(cacheName)
    .then(function(cache) { return cache.addAll(['result.min.css', './js/material.min.js']); }));
    });
    this.addEventListener('fetch', event => {
    event.respondWith(caches.match(event.request)
    .then()
    );
    });

    View Slide

  53. Caching
    const cacheName = 'pageCache';
    this.addEventListener('install', event => {
    event.waitUntil(caches.open(cacheName)
    .then(function(cache) { return cache.addAll(['result.min.css', './js/material.min.js']); }));
    });
    this.addEventListener('fetch', event => {
    event.respondWith(caches.match(event.request)
    .then(function (response) { return response || fetch(event.request); })
    );
    });

    View Slide

  54. bit.ly/sw-toolbox

    View Slide

  55. 4.65 secs
    Page Load
    2.25 secs
    500 ms

    View Slide

  56. 4.65 secs
    Page Load
    850 KB
    Page weight
    50 KB
    1 KB
    2.25 secs
    500 ms

    View Slide

  57. HTTP/2

    View Slide

  58. source: blog.cloudflare.com

    View Slide

  59. source: blog.cloudflare.com

    View Slide

  60. HTTPS

    View Slide

  61. npm install spdy

    View Slide

  62. npm install spdy
    yarn add

    View Slide

  63. const spdy = require('spdy');
    const express = require('express');
    const app = express();
    HTTP/2

    View Slide

  64. const spdy = require('spdy');
    const express = require('express');
    const app = express();
    app.get('/home', (req, res) => { res.status(200).json({message: 'ok'}); });
    spdy.createServer({
    key: fs.readFileSync('./privatekey.key'),
    cert: fs.readFileSync('./certificate.crt')
    }, app)
    .listen(8012, (err) => {
    if (err) { throw new Error(err); }
    console.log('Listening on port: 8012.'); });
    HTTP/2

    View Slide

  65. const spdy = require('spdy');
    const express = require('express');
    const app = express();
    app.get('/home', (req, res) => { res.status(200).json({message: 'ok'}); });
    spdy.createServer({
    key: fs.readFileSync('./privatekey.key'),
    cert: fs.readFileSync('./certificate.crt')
    }, app)
    .listen(8012, (err) => {
    if (err) { throw new Error(err); }
    console.log('Listening on port: 8012.'); });
    HTTP/2

    View Slide

  66. Client Side

    View Slide

  67. spdy: {
    protocols: [ 'h2', 'spdy/3.1', 'http/1.1' ],
    connection: {
    windowSize: 1024 * 1024,
    }
    }
    Config

    View Slide

  68. spdy: {
    protocols: [ 'h2', 'spdy/3.1', 'http/1.1' ],
    connection: {
    windowSize: 1024 * 1024,
    }
    }
    Config

    View Slide

  69. spdy: {
    protocols: [ 'h2', 'spdy/3.1', 'http/1.1' ],
    connection: {
    windowSize: 1024 * 1024,
    }
    }
    Config

    View Slide

  70. Techniques

    View Slide

  71. We used no
    JavaScript
    frameworks.

    View Slide

  72. We rendered
    the page
    server-side.

    View Slide

  73. We experimented
    with
    HTTP/2 Push.

    View Slide

  74. Without H2 Push

    View Slide

  75. With H2 Push

    View Slide

  76. View Slide

  77. bit.ly/http2-jake

    View Slide

  78. H2 Push
    bit.ly/server-push-http2

    View Slide

  79. We also used
    prefetch.

    View Slide

  80. View Slide

  81. View Slide


  82. View Slide

  83. Brotli =
    Better
    compression

    View Slide

  84. Brotli ~ 10%

    View Slide

  85. We tested using
    Lighthouse.

    View Slide

  86. Audit your Progressive Web App

    View Slide

  87. bit.ly/pwa-lighthouse

    View Slide

  88. 15 x less data

    View Slide

  89. 15 x less data
    3x faster

    View Slide

  90. Caching
    HTTP/2
    Techniques
    Summary

    View Slide

  91. View Slide

  92. Offline

    View Slide

  93. With Service Workers

    View Slide

  94. this.addEventListener('fetch', event => {
    };

    View Slide

  95. this.addEventListener('fetch', event => {
    // Check if the user navigated
    if (event.request.method === 'GET' &&
    event.request.headers.get('accept').includes('text/html')) {
    // Respond appropriately
    }
    };

    View Slide

  96. this.addEventListener('fetch', event => {
    // Check if the user navigated
    if (event.request.method === 'GET' &&
    event.request.headers.get('accept').includes('text/html')) {
    // Respond appropriately
    event.respondWith(
    fetch(event.request.url).catch(error => {
    // Return the offline page
    return caches.match('the-offline-page');
    }));
    }
    };

    View Slide

  97. View Slide

  98. Network
    First

    View Slide

  99. Offline Applications
    bit.ly/offline-page

    View Slide

  100. Offline Analytics
    github.com/GoogleChrome/sw-helpers

    View Slide

  101. View Slide

  102. Test your Service Worker code
    bit.ly/sw-testing

    View Slide

  103. 3rd Party Scripts

    View Slide

  104. Server Fails

    View Slide

  105. View Slide

  106. Using Service Workers

    View Slide

  107. Using Service Workers

    View Slide

  108. With Service Workers

    View Slide

  109. function timeout(delay) {
    return new Promise(function(resolve, reject) {
    setTimeout(function(){
    resolve(new Response('', { status: 408, statusText: 'Request timed out.'
    }));
    }, delay);
    });
    }

    View Slide

  110. function timeout(delay) {
    return new Promise(function(resolve, reject) {
    setTimeout(function(){
    resolve(new Response('', { status: 408, statusText: 'Request timed out.'
    }));
    }, delay);
    });
    }
    self.addEventListener('fetch', event => {
    });

    View Slide

  111. function timeout(delay) {
    return new Promise(function(resolve, reject) {
    setTimeout(function(){
    resolve(new Response('', { status: 408, statusText: 'Request timed out.'
    }));
    }, delay);
    });
    }
    self.addEventListener('fetch', event => {
    event.respondWith(
    Promise.race([timeout(6000), fetch(event.request.url)]));
    });

    View Slide

  112. bit.ly/sw-toolbox

    View Slide

  113. toolbox.router.get('/(.*)', global.toolbox.cacheFirst, {
    });

    View Slide

  114. toolbox.router.get('/(.*)', global.toolbox.cacheFirst, {
    origin: /\.google\.com$/,
    });

    View Slide

  115. toolbox.router.get('/(.*)', global.toolbox.cacheFirst, {
    origin: /\.google\.com$/,
    cache: {
    name: 'javascript',
    networkTimeoutSeconds: 4
    }
    });

    View Slide

  116. bit.ly/sw-timeout

    View Slide

  117. App-like
    Picture of mobile phones
    Look & Feel

    View Slide

  118. View Slide

  119. App-like
    Picture of mobile phones
    Look & Feel
    ❖ Manifest file

    View Slide

  120. App-like
    Picture of mobile phones
    ❖ Manifest file
    ❖ Add to Home
    Screen
    Look & Feel

    View Slide

  121. Manifest
    A simple JSON file that allows
    you to control how your app
    appears to the user

    View Slide

  122. Look and feel

    View Slide

  123. {
    lang: "en",
    background_color: "#09adec",
    name: "Settled",
    short_name: "Settled Dashboard",
    display: "standalone",
    icons:
    [
    {
    src: "./images/logo-144.png",
    sizes: "144x144",
    type: "image/png"
    }
    ],
    start_url: "/?start=a2hs",
    orientation: "portrait"
    }

    View Slide

  124. {
    lang: "en",
    background_color: "#09adec",
    name: "Settled",
    short_name: "Settled Dashboard",
    display: "standalone",
    icons:
    [
    {
    src: "./images/logo-144.png",
    sizes: "144x144",
    type: "image/png"
    }
    ],
    start_url: "/?start=a2hs",
    orientation: "portrait"
    }

    View Slide

  125. {
    lang: "en",
    background_color: "#09adec",
    name: "Settled",
    short_name: "Settled Dashboard",
    display: "standalone",
    icons:
    [
    {
    src: "./images/logo-144.png",
    sizes: "144x144",
    type: "image/png"
    }
    ],
    start_url: "/?start=a2hs",
    orientation: "portrait"
    }

    View Slide









  126. View Slide

  127. Manifest
    bit.ly/manifest-json

    View Slide

  128. Add to
    home
    screen

    View Slide

  129. Add to home screen
    1. You need a manifest.json file with a start
    URL and 144x144 PNG icon

    View Slide

  130. Add to home screen
    1. You need a manifest.json file with a start
    URL and 144x144 PNG icon
    2. Your site is using a Service Worker running
    over HTTPS

    View Slide

  131. Add to home screen
    1. You need a manifest.json file with a start
    URL and 144x144 PNG icon
    2. Your site is using a Service Worker running
    over HTTPS
    3. The user has visited your site at least twice,
    with at least five minutes between visits.

    View Slide

  132. {
    lang: "en",
    background_color: "#09adec",
    name: "Settled",
    short_name: "Settled Dashboard",
    display: "standalone",
    icons:
    [
    {
    src: "./images/logo-144.png",
    sizes: "144x144",
    type: "image/png"
    }
    ],
    start_url: "/?start=a2hs",
    orientation: "portrait"
    }

    View Slide

  133. H S

    View Slide

  134. App-like
    Picture of mobile phones
    Summary

    View Slide

  135. App-like
    Picture of mobile phones
    Summary
    ❖ Fast

    View Slide

  136. App-like
    Picture of mobile phones
    Summary
    ❖ Fast
    ❖ Reliable

    View Slide

  137. App-like
    Picture of mobile phones
    Summary
    ❖ Fast
    ❖ Reliable
    ❖ Look & Feel

    View Slide

  138. We are still learning

    View Slide

  139. View Slide

  140. Thank you!
    @deanohume

    View Slide