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

Instant Loading with Service Workers (Chrome Dev Summit '15)

Instant Loading with Service Workers (Chrome Dev Summit '15)

Presentation video: https://www.youtube.com/watch?v=jCKZDTtUA2A

Service workers can power your web app while offline, but they can also offer substantial performance benefits while online. We’ll explain how to structure your web app to optimize load time for initial and return visitors, and cover helpful service worker libraries that minimize the amount of boilerplate code you’ll have to write.

Jeffrey Posnick

November 17, 2015
Tweet

More Decks by Jeffrey Posnick

Other Decks in Technology

Transcript

  1. View Slide

  2. Instant Loading with Service Workers
    Jeff Posnick
    @jeffposnick

    View Slide

  3. App Shell
    +
    Service Worker

    View Slide

  4. ifixit-pwa.appspot.com

    View Slide

  5. ifixit-pwa.appspot.com
    2G Network, first visit
    ~ 650ms for above-the-fold

    View Slide

  6. ifixit-pwa.appspot.com
    2G Network, second visit
    ~ 200ms for above-the-fold
    (~ 560ms w/o service worker)

    View Slide

  7. ifixit-pwa.appspot.com
    2G Network, new page
    ~ 225ms for above-the-fold
    (~ 650ms w/o service worker)

    View Slide

  8. Take the Network Out of the Picture

    View Slide

  9. 1 second delay in page times leads to
    11% fewer page views
    16% decrease in customer satisfaction
    goo.gl/SOR47G

    View Slide

  10. What’s an App Shell?

    View Slide

  11. Anatomy of an App Shell
    /shell
    HTML
    +
    styles.css
    Styles
    app.js
    JavaScript
    =
    Shell

    View Slide

  12. Populating an App Shell
    iFixit
    API
    Content
    Shell

    View Slide

  13. What’s a Service Worker?

    View Slide

  14. An Air Traffic Controller for Your Requests

    View Slide

  15. The Life of a Service Worker
    No
    Service
    Worker
    install
    Event
    ↪ Cache the App Shell!

    View Slide

  16. GET /shell

    View Slide

  17. template placeholder
    Service Worker Installation
    site-wide styles
    Contents of /shell
    site-wide JS

    <br/>/* inline styles */<br/>



    <br/></body><br/>Shell<br/>

    View Slide

  18. The Life of a Service Worker
    No
    Service
    Worker
    install
    Event
    activate
    Event
    Idle
    fetch
    Event
    ↪ Cache Clean Up
    ↪ Handle Network Requests
    Stopped
    Stopped

    View Slide

  19. Service Worker fetch Interception
    GET /guide/456 fetch Event
    /shell
    (from cache)
    Shell

    View Slide

  20. Service Workers without the Work
    sw-precache
    Shell
    sw-toolbox
    Content

    View Slide

  21. Service Workers without the Work
    Case Study: goo.gl/HD6ngC

    View Slide

  22. sw-precache for Your App Shell
    sw-precache
    + =
    github.com/GoogleChrome/sw-precache
    npm install --save-dev sw-precache
    Shell

    View Slide

  23. sw-precache in Action Shell
    // [file, hash] pairs
    ...
    [js/app.js, hashABC]
    ...
    [styles/all.css, hash123]
    // Service worker code
    service-worker.js
    build/{images,js,styles}/**/*

    View Slide

  24. sw-precache in Action: Updates Shell
    // [file, hash] pairs
    ...
    [js/app.js, hashXYZ]
    ...
    [styles/all.css, hash789]
    // Service worker code
    service-worker.js

    View Slide

  25. sw-precache Command-line Interface Shell
    $ npm install -g sw-precache
    $ sw-precache --verbose
    Caching static resource "./images/back.png" (151 B)
    Caching static resource "./js/app.js" (319.06 kB)
    Caching static resource "./js/register-service-worker.js" (546 B)
    Caching static resource "./js/third-party.js" (245.03 kB)
    Caching static resource "./service-worker.js" (8.59 kB)
    Caching static resource "./styles/all.css" (1.82 kB)
    Total precache size is about 575.19 kB for 6 resources.
    service-worker.js has been generated with the service worker contents.

    View Slide

  26. gulp.babel.js Shell
    App Shell Template
    Partials/Inlines
    Request Redirection
    App Shell External
    Styles/Images/JS
    sw-toolbox Import
    swPrecache.write('service-worker.js', {
    dynamicUrlToDependencies: {
    '/shell': [...glob.sync(`${BUILD_DIR}/rev/js/**/*.js`),
    ...glob.sync(`${BUILD_DIR}/rev/styles/all*.css`),
    `${SRC_DIR}/views/index.handlebars`]
    },
    navigateFallback: '/shell',
    staticFileGlobs: [
    `${BUILD_DIR}/rev/js/**/*.js`,
    `${BUILD_DIR}/rev/styles/all*.css`],
    importScripts: [`${BUILD_DIR}/sw/sw-toolbox.js`],
    });

    View Slide

  27. sw-toolbox for Your Dynamic Content
    sw-toolbox
    github.com/GoogleChrome/sw-toolbox
    npm install --save-dev sw-toolbox
    Content

    View Slide

  28. Strategy: Cache-first, Network-fallback Content
    toolbox.cacheFirst

    View Slide

  29. Strategy: Network-first, Cache-fallback Content
    toolbox.networkFirst

    View Slide

  30. Strategy: Cache/Network Race Content
    toolbox.fastest

    View Slide

  31. Thinking Strategically Content
    toolbox.router.get('/images', toolbox.cacheFirst);
    toolbox.router.get('/api', toolbox.networkFirst);
    toolbox.router.get('/profile', toolbox.fastest);

    View Slide

  32. Why use sw-toolbox?

    View Slide

  33. Battle Lie-Fi! Content
    toolbox.router.get(
    '/path/to/image',
    toolbox.networkFirst,
    {networkTimeoutSeconds: 3}
    );

    View Slide

  34. Rein in Your Caches! Content
    toolbox.router.get(
    '/path/to/images/.*',
    toolbox.cacheFirst,
    {cache: {
    name: 'images',
    maxEntries: 6
    }}
    );

    View Slide

  35. sw-toolbox-config.js Content
    iFixit API Route
    toolbox.fastest
    fallback logic
    Image Route
    toolbox.cacheFirst
    LRU cache expiration
    toolbox.router.get('/api/2.0/(.*)', toolbox.fastest, {
    origin: /^https:\/\/www.ifixit.com$/
    });
    const MISSING_IMAGE = '/images/missing.png';
    toolbox.cache(MISSING_IMAGE);
    function imageHandler(request, values, options) {
    return toolbox.cacheFirst(request, values, options).catch(() => {
    return caches.match(MISSING_IMAGE);
    });
    }
    toolbox.router.get('/(.*)', imageHandler, {
    cache: {name: 'image-cache', maxEntries: 50},
    origin: /cloudfront.net$/
    });

    View Slide

  36. if (‘serviceWorker’ in navigator) {
    navigator.serviceWorker.register(‘sw.js’);
    } else {
    // But not all browsers
    // support service workers!
    }

    View Slide

  37. Air Traffic Controllers as Progressive Enhancement(?!?)

    View Slide

  38. Initial Visit

    View Slide

  39. Next Visit: Service Worker Supported

    View Slide

  40. Next Visit: Service Worker Not Supported

    View Slide

  41. HTTP Caching Best Practices Still Apply
    ✓ Add hashes to resource file names in your build
    ↪ /styles/all.css → /styles/all.ed34c56.css
    ✓ Use far-future HTTP caching headers
    ↪ Cache-Control: max-age=31536000
    Still plays nicely with sw-precache!

    View Slide

  42. Service Workers FTW!
    But, service workers let you:
    ✓ Serve the HTML for the landing page cache-first...
    ✓ ...even if that page is server-rendered.

    View Slide

  43. Next Steps:

    View Slide

  44. Embrace Your Shell!

    View Slide

  45. iFixit API Demo
    ifixit-pwa.appspot.com
    github.com/GoogleChrome/sw-precache/
    tree/master/app-shell-demo

    View Slide

  46. sw-precache Codelab
    www.code-labs.io/codelabs/sw-precache/

    View Slide

  47. Polymer Demo
    zuperkulblog.appspot.com
    github.com/polymerlabs/
    zuperkulblog-progressive

    View Slide

  48. github.com/Google/web-starter-kit

    View Slide

  49. “Vanilla JS” App Shell
    app-shell.appspot.com
    github.com/GoogleChrome/application-shell

    View Slide

  50. Instant Loading with Service Workers
    Jeff Posnick
    @jeffposnick

    View Slide

  51. View Slide