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

The Hitchhiker's Guide to the Front-End Performance, 2018 edition

The Hitchhiker's Guide to the Front-End Performance, 2018 edition

Optimizing applications to offer the best user experience isn't something trivial even for the most skilled front-end developers; given Murphy's law, browsers don't always know what critical resources they should load first, huge code bundles and users' slow network connections make them wait more seconds than they want to and, once the whole download is finished, we know that JavaScript can even take a few more seconds to process.

Thankfully there's a lot we can do to give our users a much better experience: preloading, prefetching, code splitting, common chunks, dynamic imports, service workers, web workers, JavaScript compile-time optimization and so on. Yet, in a world where all we hear is PWA hype driven development ™, how these different pieces of the web interact to bring our users a real meaningful better experience is often not well understood, explained or put in practice.

In this talk I'll explain how to ship way faster front-end bundles and share a few general data-driven techniques and performance patterns learnt during my journey building geodata visualization platforms at scale focused on three aspects: faster loading times, better performance and smarter mobile data usage.

Matheus Albuquerque

September 15, 2018
Tweet

More Decks by Matheus Albuquerque

Other Decks in Programming

Transcript

  1. ˜ @ythecombinator on the webs ˜ Engineering Leader, Front-End @beakyn

    ˜ previously @Apple Developer Academy and unemployed indie developer software consultant ˜ addicted to emojis, memes and beer ˜ this ( ) means #after
  2.  “Feijão com Arroz” seal ˜ GZIP everything ˜ Minify

    both CSS and JS ˜ HTML must be compressed ˜ CSS goes on <head> ˜ JS goes lastly on </body> ˜ Optimize all the images (e.g. svgo)
  3. "Write modern, idiomatic JavaScript, and let the JavaScript engine worry

    about making it fast." - Mathias Bynens, BrazilJS 2018
  4. Before version 5.9 of V8 came out, the engine used

    two compilers: ˜ Full Codegen A simple and very fast compiler that produced simple and relatively slow machine code ˜ Crankshaft A more complex (Just-In-Time) optimizing compiler that produced highly-optimized code
  5. Optimization Killers ~ Generators and async functions ~ for-of and

    destructuring ~ try-catch and try-finally ~ Compound let or const assignment ~ Object literals that contain __proto__, or get or set declarations. ~ debugger or with statements ~ Literal calls to eval() ~ …
  6. Performance cliffs in Crankshaft (function good() {
 const start =

    Date.now();
 for (var i = 0; i < 1e8; i++) {}
 console.log(Date.now() - start);
 })(); ˜80ms (function bad() {
 const start = Date.now();
 for (var i = 0; i < 1e8; i++) {}
 console.log(Date.now() - start);
 const whatever = 1;
 })(); ˜230ms
  7. Performance cliffs in Crankshaft (function good() {
 const start =

    Date.now();
 for (var i = 0; i < 1e8; i++) {}
 console.log(Date.now() - start);
 })(); (function bad() {
 const start = Date.now();
 for (var i = 0; i < 1e8; i++) {}
 console.log(Date.now() - start);
 const whatever = 1;
 })(); ˜3x slowdown with Crankshaft
  8. The new execution pipeline is built on top of Ignition,

    V8’s interpreter, and TurboFan, V8’s newest optimizing compiler.
  9. Optimization Killers ~ Generators and async functions ~ for-of and

    destructuring ~ try-catch and try-finally ~ Compound let or const assignment ~ Object literals that contain __proto__, or get or set declarations. ~ debugger or with statements ~ Literal calls to eval() ~ …
  10. "Write modern, idiomatic JavaScript, and let the JavaScript engine worry

    about making it fast." - Mathias Bynens, BrazilJS 2018
  11. ˜ What can %& do… ˜ Avoid pre-allocating large arrays

    ˜ Don’t delete elements in arrays ˜ What it does… Sparse arrays which don’t have every element inside them are a hash table. Elements in such arrays are more expensive to access.
  12. ˜ What can %& do… ˜ Always instantiate your object

    properties in the same order ˜ Assign all of an object’s properties in its constructor
  13. function Point(x, y) { this.x = x; this.y = y;

    } var p1 = new Point(1, 2); Point C0
  14. function Point(x, y) { this.x = x; this.y = y;

    } var p1 = new Point(1, 2); Point C1 For x, see offset 0 C0 If x is added, transition to C1
  15. Point C2 function Point(x, y) { this.x = x; this.y

    = y; } var p1 = new Point(1, 2); C1 For x, see offset 0 If y is added, transition to C2 For x, see offset 0 For y, see offset 1 C0 If x is added, transition to C1
  16. function Point(x, y) { this.x = x; this.y = y;

    } var p1 = new Point(1, 2); p1.a = 5; p1.b = 6; var p2 = new Point(3, 4); p2.b = 7; p2.a = 8;
  17. function Point(x, y) { this.x = x; this.y = y;

    } var p1 = new Point(1, 2); p1.a = 5; p1.b = 6; var p2 = new Point(3, 4); p2.b = 7; p2.a = 8;
  18. function Point(x, y) { this.x = x; this.y = y;

    } var p1 = new Point(1, 2); p1.a = 5; p1.b = 6; var p2 = new Point(3, 4); p2.b = 7; p2.a = 8;
  19. ˜ Always instantiate your object properties in the same order

    ˜ Assign all of an object’s properties in its constructor
  20. ˜ Connecting to critical origins (preconnect) ˜ Asset for current

    page (preload) ˜ Asset for future navigation (prefetch)
  21. ˜ Connecting to critical origins (preconnect) ˜ Asset for current

    page (preload) ˜ Asset for future navigation (prefetch)
  22. ˜ What it does… Preconnect allows the browser to setup

    early connections before an HTTP request is actually sent to the server. This includes: ˜ DNS lookups ˜ TLS negotiations ˜ TCP handshakes This in turn: ✔ Eliminates roundtrip latency ✔ Saves time for users
  23. ˜ Bring me the ! 100MS 200MS 300MS 400MS 500MS

    600MS 700MS HTML CSS FONT 1 FONT 2 Fonts start loading Fonts rendered
  24. ˜ Bring me the ! 100MS 200MS 300MS 400MS 500MS

    600MS 700MS HTML CSS FONT 1 FONT 2 Fonts start loading Fonts rendered FONT 1 FONT 2
  25. ˜ Connecting to critical origins (preconnect) ˜ Asset for current

    page (preload) ˜ Asset for future navigation (prefetch)
  26. ˜ What it does… Some of the benefits of the

    preload directive include: ✔ Gives the browser the ability to determine the resource type (it can tell if the same resource can be reused in the future) ✔ The browser can determine if the request is compliant with the content security policy ✔ The browser can send the appropriate accept headers based on resource type
  27. ˜ Connecting to critical origins (preconnect) ˜ Asset for current

    page (preload) ˜ Asset for future navigation (prefetch)
  28. ˜ What it does… ✔ Fetch resources in the background

    (idle time) ✔ Store them in the browser’s cache It can be:
  29. Link Prefetching DNS Prefetching Prerendering ˜ What it does… Allows

    the browser to fetch resources, store them in cache, assuming that the user will request them. <link rel="prefetch" href="/uploads/images/pic.png"> ˜ What can %& do…
  30. Link Prefetching DNS Prefetching Prerendering ˜ What it does… Allows

    the browser to perform DNS lookups on a page in the background while the user is browsing. <link rel=“dns-prefetch” href="#$fonts.googleapis.com"> ˜ What can %& do…
  31. Link Prefetching DNS Prefetching Prerendering ˜ What it does… Allows

    the browser to render the entire page in the background, all the assets of a document. <link rel=“prerender” href=“https://xandaviao.com.br/”> ˜ What can %& do…
  32. Link Prefetching DNS Prefetching Prerendering ˜ What it does… Allows

    the browser to render the entire page in the background, all the assets of a document. <link rel=“prerender” href=“https://xandaviao.com.br/”> ˜ What can %& do… ⚠ ❌ ❌ ⚠
  33. Link Prefetching DNS Prefetching Prerendering ˜ What it does… Allows

    the browser to render the entire page in the background, all the assets of a document. <link rel=“prerender” href=“https://xandaviao.com.br/”> ˜ What can %& do… ✘ You want to be more careful with prerendering as it is resource heavy and can cause bandwidth waste, especially on mobile devices
  34. %%%& A script is to be loaded with critical importance

    as it is necessary for the core user experience ''( <script src=foo importance=critical> %%%& An image is to be loaded with high importance. It could be important but not critical to the overall experience loading up. ''( <img src=foo importance=high> %%%& It can be used to indicate low importance/non-blocking style which isn't impacting the core experience. ''( <link rel=stylesheet href=foo importance=low>
  35. #$ First import(/* webpackPrefetch: 3 */ "assets/images/foo.jpg"); #$ Second import(/*

    webpackPrefetch: 2 */ "modules/foo"); #$ Last import(/* webpackPrefetch: 1 */ “modules/bar");
  36. Preloaded Chunk Prefetched Chunk X ˜ Starts loading in parallel

    to the parent chunk ˜ Focuses on current navigation ˜ Fetches resources with high-priority ˜ Is instantly downloaded ˜ Starts after the parent chunk finish ˜ Focuses on fetching resources for the next navigation ˜ Fetches resources with low priority ˜ Is downloaded in browser idle time
  37. ˜ Connecting to critical origins (preconnect) ˜ Asset for current

    page (preload) ˜ Asset for future navigation (prefetch)
  38. ˜ Avoid invisible text while web fonts are loading ˜

    Reduce render blocking scripts and stylesheets ˜ Server-side render stuff
  39. ˜ Avoid invisible text while web fonts are loading ˜

    Reduce render blocking scripts and stylesheets ˜ Server-side render stuff
  40. ˜ What says… ˜ What can %& do… @font-face {

    font-family: "Open Sans Regular"; src: url(“./OpenSans-Regular-BasicLatin.woff2") format("woff2"); font-display: swap; }
  41. ˜ What says… ˜ What can %& do… @font-face {

    font-family: "Open Sans Regular"; src: url(“./OpenSans-Regular-BasicLatin.woff2") format("woff2"); font-display: swap; } ˜ What it does… The initial font displayed is the first system font in the stack. When the custom font has loaded, it will kick in and replace the system font that was initially displayed.
  42. ˜ Avoid invisible text while web fonts are loading ˜

    Reduce render blocking scripts and stylesheets ˜ Server-side render stuff
  43. ˜ Avoid invisible text while web fonts are loading ˜

    Reduce render blocking scripts and stylesheets ˜ Server-side render stuff
  44. ˜ Avoid invisible text while web fonts are loading ˜

    Reduce render blocking scripts and stylesheets ˜ Server-side render stuff
  45. ˜ Audit your assets regularly ˜ Code Split (Routes, Components,

    Vendor bundles) + Dynamic Import stuff ˜ Remove unused library code + Tree Shake
  46. ˜ Audit your assets regularly ˜ Code Split (Routes, Components,

    Vendor bundles) + Dynamic Import stuff ˜ Remove unused library code + Tree Shake
  47. ˜ Audit your assets regularly ˜ Code Split (Routes, Components,

    Vendor bundles) + Dynamic Import stuff ˜ Remove unused library code + Tree Shake
  48. ˜ Audit your assets regularly ˜ Code Split (Routes, Components,

    Vendor bundles) + Dynamic Import stuff ˜ Remove unused library code + Tree Shake
  49. ˜ Audit your assets regularly ˜ Code Split (Routes, Components,

    Vendor bundles) + Dynamic Import stuff ˜ Remove unused library code + Tree Shake
  50. ✔ Static sites ✔ In control of your Apache or

    Nginx servers ✔ No budget for this ✘ Dynamic content / Rapidly changing websites
  51. Among the 40+ optimisation filters available in mod_pagespeed are: ✔

    optimization, compression and resizing of images; ✔ concatenation, minification, and inlining of your CSS and JavaScript; ✔ cache extension, domain sharding, and domain rewriting; ✔ deferred loading of JavaScript and image resources
  52. ˜ Code coverage in DevTools (Page load, runtime) ˜ Lighthouse

    Coverage Audit ˜ Remove unused code to improve load time ˜ Write regression tests
  53. ˜ Code coverage in DevTools (Page load, runtime) ˜ Lighthouse

    Coverage Audit ˜ Remove unused code to improve load time ˜ Write regression tests
  54. ˜ Code coverage in DevTools (Page load, runtime) ˜ Lighthouse

    Coverage Audit ˜ Remove unused code to improve load time ˜ Write regression tests
  55. ˜ Code coverage in DevTools (Page load, runtime) ˜ Lighthouse

    Coverage Audit ˜ Remove unused code to improve load time ˜ Write regression tests
  56. ˜ Code coverage in DevTools (Page load, runtime) ˜ Lighthouse

    Coverage Audit ˜ Remove unused code to improve load time ˜ Write regression tests
  57. ˜ GUI ˜ ImageOptmin (Mac) XNConvert (Cross-platform) ˜ Build ˜

    imagemin libvips ˜ CDN ˜ Cloudinary Imgix Fastly Akamai ˜ CDN ˜ (self-hosted) Thumbor ImageFlow ˜ What can %& do…
  58. ˜ GUI ˜ ImageOptmin (Mac) XNConvert (Cross-platform) ˜ Build ˜

    imagemin libvips ˜ CDN ˜ Cloudinary Imgix Fastly Akamai ˜ CDN ˜ (self-hosted) Thumbor ImageFlow
  59. <img src="banda_magnificos.gif"> 7.3mb <video autoplay muted playinline> <source src="banda_magnificos.mp4" type="video/mp4">

    </video> 1.3MB <video autoplay muted playinline> <source src=“banda_magnificos.webm” type=“video/webm"> </video> 960kb 80%+ savings
  60. ˜ Use referentially equal stuff ˜ Use PureComponent/memo (when it

    makes sense) ˜ Take benefit from techniques like windowing
  61. ˜ Progressive Web Apps (PWAs) ˜ Devops/Something-as-a-Service ˜ Blockchain ˜

    Machine Learning/Deep Learning/ Neural Networks (& other Artificial Intelligence slangs I’ve got no idea of)
  62. ˜ Progressive Web Apps (PWAs) ˜ Devops/Something-as-a-Service ˜ Blockchain ˜

    Machine Learning/Deep Learning/ Neural Networks (& other Artificial Intelligence slangs I’ve got no idea of)
  63. #$ Require GuessPlugin const {GuessPlugin} = require('guess-webpack'); #$ Add it

    in the end of your webpack #$ plugin configuration GuessPlugin({ GA: 'GA_VIEW_ID' })
  64. ˜ GA Module fetches structured data from Google Analytics ˜

    Guess Parser parses an application in order to create the mapping between routes and JavaScript bundles ˜ Guess Webpack Plugin automates the process of applying data-driven bundling & pre-fetching in React & Angular apps
  65. Its goal is to replace the manual decision making with

    an automated data-driven approach. Focusing on: ˜ Single-page applications ˜ Static content sites ˜ Framework-based static sites