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

LDNWebPerf March 2017 - Dean Hume

LDNWebPerf March 2017 - Dean Hume

As web developers, we’ve never been luckier. We have amazing technologies such as HTTP/2, Progressive Web Apps, and easy access to the Cloud, just to name a few. With these technologies at our fingertips, we are able to build fast, engaging and resilient web apps for our users.

At Settled, we set out to build a new dashboard for our customers using the features of Progressive Web Apps and HTTP/2. We wanted to build an offline-first application that allowed our users to quickly and easily access their information on the go regardless of their network connection. We noticed an immediate change; our users spent twice as long on the site, they consumed 15x less data, and enjoyed a 3x faster load times. In this presentation, we’ll cover our journey and the lessons that we learnt along the way as well as many real-world, practical tips that you can use when building your own web apps.

More Decks by London Web Performance Group

Other Decks in Technology

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. ● Was accessible on any device
    We needed an experience that:

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  11. ● Was accessible on any device
    ● Was fast
    ● Works with little or no internet
    connection
    ● Used one codebase
    ● Had 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

    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

    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. const cacheName = ‘pageCache’;
    Caching

    View Slide

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

    View Slide

  51. 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']);
    })
    );
    });
    Caching

    View Slide

  52. 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);
    })
    );
    });
    Caching

    View Slide

  53. bit.ly/sw-toolbox

    View Slide

  54. ★ Fresh visit - 2 secs
    ★ Cached visit - 500 ms
    ★ Less load on the
    server

    View Slide

  55. HTTP/2

    View Slide

  56. source: blog.cloudflare.com

    View Slide

  57. source: blog.cloudflare.com

    View Slide

  58. HTTPS

    View Slide

  59. npm install spdy

    View Slide

  60. npm install spdy
    yarn add

    View Slide

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

    View Slide

  62. const spdy = require('spdy');
    const express = require('express');
    const app = express();
    // Any incoming requests
    app.get('/home', (req, res) => { res.status(200).json({message: 'ok'}); });
    HTTP/2

    View Slide

  63. const spdy = require('spdy');
    const express = require('express');
    const app = express();
    // Any incoming requests
    app.get('/home', (req, res) => { res.status(200).json({message: 'ok'}); });
    // Create the Server
    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

  64. Client Side

    View Slide

  65. Server Side

    View Slide

  66. Techniques

    View Slide

  67. We used no
    JavaScript
    frameworks.

    View Slide

  68. We rendered
    the page
    server-side.

    View Slide

  69. We experimented
    with
    HTTP/2 Push.

    View Slide

  70. View Slide

  71. Without H2 Push

    View Slide

  72. With H2 Push

    View Slide

  73. View Slide

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

    View Slide

  75. We also used
    prefetch.

    View Slide

  76. View Slide

  77. View Slide


  78. View Slide

  79. We tested using
    Lighthouse.

    View Slide

  80. Audit your Progressive Web App

    View Slide

  81. bit.ly/pwa-lighthouse

    View Slide

  82. 15 x less data

    View Slide

  83. 15 x less data
    3x faster

    View Slide

  84. Caching
    HTTP/2
    Techniques
    Summary

    View Slide

  85. View Slide

  86. Offline

    View Slide

  87. With Service Workers

    View Slide

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

    View Slide

  89. 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

  90. 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

  91. View Slide

  92. Network
    First

    View Slide

  93. Offline Applications
    bit.ly/offline-page

    View Slide

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

    View Slide

  95. 3rd Party Scripts

    View Slide

  96. Server Fails

    View Slide

  97. View Slide

  98. Using Service Workers

    View Slide

  99. Using Service Workers

    View Slide

  100. With Service Workers

    View Slide

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

    View Slide

  102. 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

  103. 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

  104. bit.ly/sw-toolbox

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  108. bit.ly/sw-timeout

    View Slide

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

    View Slide

  110. View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  114. Look and feel

    View Slide

  115. {
    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

  116. {
    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

  117. {
    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









  118. View Slide

  119. Manifest
    bit.ly/manifest-json

    View Slide

  120. Add to
    home
    screen

    View Slide

  121. Add to home screen
    1. You need a manifest.json file

    View Slide

  122. Add to home screen
    1. You need a manifest.json file
    2. Your manifest file needs a start URL

    View Slide

  123. Add to home screen
    1. You need a manifest.json file
    2. Your manifest file needs a start URL
    3. You need a 144x144 PNG icon

    View Slide

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

    View Slide

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

    View Slide

  126. {
    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

  127. H
    S

    View Slide

  128. App-like
    Picture of mobile phones
    Summary

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  132. What’s still to come?

    View Slide

  133. Push Notifications

    View Slide

  134. Web Share

    View Slide

  135. Web Share
    bit.ly/webshare-api

    View Slide

  136. Brotli

    View Slide

  137. We are still learning

    View Slide

  138. View Slide

  139. View Slide

  140. Thank you!
    @deanohume

    View Slide