Save 37% off PRO during our Black Friday Sale! »

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

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

Presentation video:

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


  1. None
  2. Instant Loading with Service Workers Jeff Posnick @jeffposnick

  3. App Shell + Service Worker


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

  6. 2G Network, second visit ~ 200ms for above-the-fold (~

    560ms w/o service worker)
  7. 2G Network, new page ~ 225ms for above-the-fold (~

    650ms w/o service worker)
  8. Take the Network Out of the Picture

  9. 1 second delay in page times leads to 11% fewer

    page views 16% decrease in customer satisfaction
  10. What’s an App Shell?

  11. Anatomy of an App Shell /shell HTML + styles.css Styles

    app.js JavaScript = Shell
  12. Populating an App Shell iFixit API Content Shell

  13. What’s a Service Worker?

  14. An Air Traffic Controller for Your Requests

  15. The Life of a Service Worker No Service Worker install

    Event ↪ Cache the App Shell!
  16. GET /shell

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

    site-wide JS <head> <style> /* inline styles */ </style> </head> <body> <!-- template insertion point --> <script src="app.js"> </body> Shell
  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
  19. Service Worker fetch Interception GET /guide/456 fetch Event /shell (from

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

  21. Service Workers without the Work Case Study:

  22. sw-precache for Your App Shell sw-precache + = npm

    install --save-dev sw-precache Shell
  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}/**/*
  24. sw-precache in Action: Updates Shell // [file, hash] pairs ...

    [js/app.js, hashXYZ] ... [styles/all.css, hash789] // Service worker code service-worker.js
  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.
  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`], });
  27. sw-toolbox for Your Dynamic Content sw-toolbox npm install --save-dev

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

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

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

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

  32. Why use sw-toolbox?

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

  34. Rein in Your Caches! Content toolbox.router.get( '/path/to/images/.*', toolbox.cacheFirst, {cache: {

    name: 'images', maxEntries: 6 }} );
  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:\/\/$/ }); 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: /$/ });
  36. if (‘serviceWorker’ in navigator) { navigator.serviceWorker.register(‘sw.js’); } else { //

    But not all browsers // support service workers! }
  37. Air Traffic Controllers as Progressive Enhancement(?!?)

  38. Initial Visit

  39. Next Visit: Service Worker Supported

  40. Next Visit: Service Worker Not Supported

  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!
  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.
  43. Next Steps:

  44. Embrace Your Shell!

  45. iFixit API Demo tree/master/app-shell-demo

  46. sw-precache Codelab

  47. Polymer Demo zuperkulblog-progressive


  49. “Vanilla JS” App Shell

  50. Instant Loading with Service Workers Jeff Posnick @jeffposnick

  51. None