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

PWAs: the Application Shell & the well of surpr...

PWAs: the Application Shell & the well of surprises

When it comes to performance, we’ll usually take all the help we can get. The app shell model – an architecture for building PWAs – can make a huge difference… but better keep in mind it may hold a few surprises for you.

Stratos Pavlakis

November 30, 2018
Tweet

More Decks by Stratos Pavlakis

Other Decks in Programming

Transcript

  1. domContentLoaded navigationStart loadEventEnd time to first paint time to first

    paint time to interactive time to first byte frames per second page load time speed Index time to first ad first contentful paint first meaningful paint hero elements domainLookupStart
  2. Request Page Start building DOM Build CSSOM wait block GET


    /page Network Rendering GET
 /style GET
 /js CSS JS HMTL
  3. Request Page Start building DOM Build CSSOM Run JS wait

    Continue DOM block GET
 /page Network Rendering GET
 /style GET
 /js CSS JS HMTL
  4. Request Page Start building DOM Build CSSOM Run JS wait

    Continue DOM block style / layout / paint / comp GET
 /page Network Rendering GET
 /style GET
 /js CSS JS HMTL
  5. Request Page Start building DOM Build CSSOM Run JS wait

    Continue DOM block styl GET
 /page Network Rendering GET
 /style GET
 /js CSS JS HMTL
  6. distance light in vacuum light in fiber RTT London 5,585km

    19ms 28ms 56ms Sydney 15,993km 53ms 80ms 160ms Thess 7,695km 26ms 38ms 76ms - Browser Networking, Ilya Grigorik Getting a byte from New York
  7. Client (London) Server (New York) 0 ms SYN 28 ms

    SYN ACK ACK 56 ms 140 ms ChangeCipherSpec
 Finished ClientHello 84 ms ClientKeyExchange
 ChangeCipherSpec 
 Finished
 ServerHello Cert
 ServerHelloDone
 112 ms 168 ms TCP TLS
  8. Client (London) Server (New York) 0 ms SYN 28 ms

    SYN ACK ACK 56 ms Application 196 ms 140 ms ChangeCipherSpec
 Finished ClientHello 84 ms ClientKeyExchange
 ChangeCipherSpec 
 Finished
 ServerHello Cert
 ServerHelloDone
 112 ms 168 ms TCP TLS
  9. Client (London) Server (New York) 0 ms SYN 28 ms

    SYN ACK ACK 56 ms Application 196 ms 140 ms ChangeCipherSpec
 Finished ClientHello 84 ms ClientKeyExchange
 ChangeCipherSpec 
 Finished
 ServerHello Cert
 ServerHelloDone
 112 ms 168 ms Application 224 ms TCP TLS
  10. Client (London) Server (New York) 0 ms SYN 28 ms

    SYN ACK ACK 56 ms Application 196 ms 140 ms ChangeCipherSpec
 Finished ClientHello 84 ms ClientKeyExchange
 ChangeCipherSpec 
 Finished
 ServerHello Cert
 ServerHelloDone
 112 ms 168 ms Application 224 ms 11011010 TCP TLS
  11. Delay User Perception 0 - 100ms Instant 100 - 300ms

    Perceptible delay 300 - 1000ms Machine is working 1000ms+ Likely mental context switch time and user perception Browser Networking - Ilya Grigorik
  12. 1

  13. Html Css Js Img Html Css Js Img Html Css

    Js Img Html Css Js Img Html Css Js Img 1 Edge Caching Html Css Js Img
  14. Html Css Js Img Html Css Js Img Html Css

    Js Img Html Css Js Img Html Css Js Img 1 Edge Caching Html Css Js Img
  15. Html Css Js Img Html Css Js Img Html Css

    Js Img Html Css Js Img Html Css Js Img 1 Edge Caching Html Css Js Img Static / JAMStack
  16. 2

  17. 3

  18. 3 Service Workers •Proxies of our own •Live in the

    browser •Domain & path scoped •Async by spec
  19. 3 Service Workers •Proxies of our own •Live in the

    browser •Domain & path scoped •Async by spec •Utilize Cache API
  20. 3 Service Workers •Proxies of our own •Live in the

    browser •Domain & path scoped •Async by spec •Utilize Cache API •Run on separate thread
  21. Request Page Start building DOM Build CSSOM Run JS wait

    Continue DOM block style / layout / paint / comp GET
 /page GET
 /style GET
 /js css js html with a critical path to improve…
  22. What can service workers do? a few front end Devs

    That would only involve… Cache stuff Even… cache the HTML document
  23. What can service workers do? a few front end Devs

    That would only involve… It would be just cross cut change that would eliminate the network Cache stuff Even… cache the HTML document
  24. What can service workers do? a few front end Devs

    That would only involve… It would be just cross cut change that would eliminate the network once and for all !! Cache stuff Even… cache the HTML document
  25. the plan • Create a proof of concept • Deploy

    on staging • Work on the details while feedback is coming • Tweak a few things • Go Live!
  26. sw.js var cacheFiles = [ “./index-shell.html”, "./js/app.js", "./css/style.css" ]; self.addEventListener("install",

    e "=> { e.waitUntil( caches.open(cacheName).then(cache "=> { return cache.addAll(cacheFiles); }) ); });
  27. "./js/app.js", "./css/style.css" ]; self.addEventListener("install", e "=> { e.waitUntil( caches.open(cacheName).then(cache "=>

    { return cache.addAll(cacheFiles); }) ); }); self.addEventListener("fetch", function(e) { if (e.request.url.match(/\/index.html/)) { e.respondWith(caches.match('/index-shell.html')); } });
  28. navigator.serviceWorker .register(“/sw.js”, { scope: "./" }) .then(() "=> { console.log(“[ServiceWorker]

    Registered"); }) .catch(err "=> { console.log(“[ServiceWorker] Failed to Register", err); }); index.html
  29. Surprise #2 /index.html meet Opaque responses • Responses to requests

    made to a remote origin 
 when CORS is not enabled
  30. Surprise #2 /index.html meet Opaque responses • Responses to requests

    made to a remote origin 
 when CORS is not enabled • status == 0
  31. Surprise #2 /index.html meet Opaque responses • Responses to requests

    made to a remote origin 
 when CORS is not enabled • status == 0 • no access to headers
  32. Surprise #2 /index.html meet Opaque responses • Responses to requests

    made to a remote origin 
 when CORS is not enabled • status == 0 • no access to headers • no access to body
  33. Surprise #2 /index.html meet Opaque responses • Responses to requests

    made to a remote origin 
 when CORS is not enabled • status == 0 • no access to headers • no access to body • Using a CDN? => your assets on a remote origin
  34. Surprise #2 /index.html meet Opaque responses const request = new

    Request( 'https:"//no-cors-cdn.com/style.css', { mode: 'no-cors' } ); fetch(request).then(response "=> cache.put(request, response) );
  35. Surprise #2 /index.html meet Opaque responses Configure CORS for all

    your cached assets <link crossorigin=‘anonymous’ /> Your JS should already be so for error monitoring
  36. Detail #1 /index.html App has been updated. Click here to

    reload •When? •Won’t it become annoying? •Backwards compatibility?
  37. Detail #1 /index.html App has been updated. Click here to

    reload Treat your web app as a mobile app
  38. Detail #1 /index.html App has been updated. Click here to

    reload •Set ShellVersion in index.html •Add ShellVersion HTTP Header 
 to all XHR requests •Bump it on every release/deploy
 based on watched files
  39. Detail #1 /index.html App has been updated. Click here to

    reload •Set minimum supported version •Return client error HTTP status 
 (e.g. 430) if below minimum
  40. Detail #1 /index.html App has been updated. Click here to

    reload Show update prompt up to 2 times/ day for + on 430s.
  41. Detail #2 /index.html no big deal bug? ENV.SW_TYPE=“NOOP” self.addEventListener('install', function

    () { self.skipWaiting(); console.log('NOOP service worker installed'); }); self.addEventListener('activate', function (event) { event.waitUntil(clients.claim()); console.log('NOOP service worker activated'); });
  42. Detail #2 /index.html HUGE deal bug? ENV.SW_TYPE=“DESTROYER” self.addEventListener('install', function (e)

    { self.skipWaiting(); }); self.addEventListener('activate', function (e) { self.registration.unregister() .then(function () { return self.clients.matchAll(); }) .then(function (clients) { clients.forEach(client "=> client.navigate(client.url)); });
  43. Surprise #3 /index.html We removed SSR. To go beyond user

    perceived performance and ACTUALLY load faster, you need to approach the idea of… offline first
  44. Surprise #3 /index.html Offline first (simple case) Serve cached content

    from IDB or localStorage, while fetching fresh data from the server.
  45. Surprise #3 /index.html 1.Sign in as Bob 2.Sign out 3.Sign

    in as Alice 4.What does Alice see? caching the user specific content, poses this problem
  46. Surprise #3 /index.html /app_shell /index.html?uid=4w321r /signin + Scope IDB, Storage

    keys under this UID e.g. “/uid/42321/avatarUrl” match with UID