$30 off During Our Annual Pro Sale. View Details »

Lessons Learned Sciencing The Web

Addy Osmani
November 11, 2017

Lessons Learned Sciencing The Web

My talk from FFConf 2017.

Addy Osmani

November 11, 2017
Tweet

More Decks by Addy Osmani

Other Decks in Technology

Transcript

  1. @addyosmani

    View Slide

  2. @addyosmani

    View Slide

  3. LOAD ONLY WHAT YOU NEED
    WHEN YOU NEED IT
    n

    View Slide

  4. DON’T BE BIG
    ✂ Code-split your JavaScript
    Compress resources
    ⚡ Minify & optimize *.*
    Tree-shake modules
    Respect data plans
    Don’t over-do Web Fonts
    ONLY LOAD WHAT YOU NEED
    Lazy-load non-critical resources
    Preconnect to important origins
    Preload critical resources
    Minimize redirects & round-trips
    ONLY LOAD WHAT CHANGED
    Cache resources effectively
    Be network resilient with Service Workers
    LOADING BEST PRACTICES

    View Slide

  5. User Expectations

    View Slide

  6. View Slide

  7. RESPONSE
    ANIMATION
    IDLE
    LOAD
    RAIL
    Evolving

    View Slide

  8. First Paint
    First Meaningful Paint
    Time To Interactive
    User happiness metrics
    First Contentful Paint

    View Slide

  9. Time to Interactive
    <5s
    on an average mobile
    device over 3G
    *2s on repeat-load a:er Service Worker registered
    goal

    View Slide

  10. Latencies are significantly higher than a wired connection

    View Slide

  11. View Slide

  12. Can we data-science
    the web?

    View Slide

  13. View Slide

  14. View Slide

  15. View Slide

  16. THIS CAN’T
    GO WRONG.

    View Slide

  17. NEW GAME
    OPTIONS
    A ROAD RASH RIFF

    View Slide

  18. PLAYER 1
    REMY
    LEVEL 1
    A TOTALLY SAFE ROAD

    View Slide

  19. STAGE 1: MEASURE
    REMY
    REMY

    View Slide

  20. Chrome DevTools
    Lighthouse
    WebPageTest
    TOOLS TO SCIENCE THE WEB
    Synthetic lab conditions
    Real-world
    RUM
    Synthetic health of the web
    Puppeteer
    ~500K sites
    BETA

    View Slide

  21. Queryable RUM for
    the web?

    View Slide

  22. bit.ly/introducing-crux

    View Slide

  23. Origin
    Form Factor
    Effective Connection Type (e.g 3G, 4G)
    First Paint
    First ContentFul Paint
    domContentLoaded
    onLoad

    View Slide

  24. // Network type that browser uses

    navigator.connection.type
    > 'wifi'

    // New: Effective connection type
    // using rtt and downlink values

    navigator.connection.effectiveType
    > '2G'
    I want to adapt serving based on estimated network quality
    BEFORE AFTER
    For more on navigator.connection.*
    See ‘Building a modern media experience’
    Chrome 62

    View Slide

  25. RUM
    Chrome UX Report

    View Slide

  26. STAGE 2: OPTIMIZE
    REMY

    View Slide

  27. JAVASCRIPT

    View Slide

  28. “Networks, CPUs and disks all
    hate you. On the client, you
    pay for what you send in
    ways you can't easily see”
    - Alex Russell, Chrome

    View Slide

  29. http://beta.httparchive.org
    Using Dev Tools mobile emulation, Moto G4 calibrated CPU, Cable (5/1mbps, 28ms)
    STATE OF JAVASCRIPT ON MOBILE
    1MB 600KB+ 300KB+
    10% sites 25% sites 50% sites

    View Slide

  30. View Slide

  31. View Slide

  32. View Slide

  33. JavaScript has a cost.
    Fast = Fast at
    Parse
    Eval
    Download
    On mobile devices

    View Slide

  34. 2017 JavaScript Parse Costs
    Average Phone
    ~1MB JavaScript (uncompressed)

    View Slide

  35. JavaScript Parse Cost On Mobile - CNN
    ~9s difference to the A11
    With thanks to Pat Meenan

    View Slide

  36. PRPL Pattern
    USED BY SITES LIKE
    SUPPORTED BY CLIs

    View Slide

  37. Where do mobile sites spend their time loading?
    With thanks to Camillo and Mathias @ V8
    Average
    Housing
    Forbes
    Treebo
    Twitter
    Trivago
    Lancome
    Tech Today
    OLACabs
    Wego
    Konga

    View Slide

  38. Removing unused code can reduce network
    transmission times, CPU-intensive code
    parsing, and memory overhead

    View Slide

  39. CODE COVERAGE

    View Slide

  40. 40%
    SITES MAY USE ONLY
    OF THE JAVASCRIPT THEY LOAD
    UPFRONT.
    With thanks to [email protected]
    JS CODE COVERAGE OF TOP 50 SITES

    View Slide

  41. LEARN FROM
    GAME DEVELOPERS

    View Slide

  42. BAKE ONLY WHAT A SECTION
    REQUIRES INTO BUNDLES THAT
    CAN BE LOADED AS NEEDED.
    n

    View Slide

  43. Code-splitting
    // Defines a “split-point” for a separate bundle
    require.ensure([], () => {
    const profile = require('./UserProfile', cb);
    });
    import('./UserProfile')
    .then(loadRoute(cb))
    .catch(errorLoading)
    Webpack 2+
    Webpack 1
    Also see Splittable, Closure Compiler
    or Browserify

    View Slide

  44. Minify _everything_
    Babelified ES5 w/Uglify
    ES2015+ with babel-minify
    css-loader + minimize:true
    Code-splitting
    Dynamic import()
    Route-based chunking
    Tree-shaking
    Webpack 2+ with Uglify
    RollUp
    DCE w/ Closure Compiler
    Optimize “Vendor” libs
    NODE_ENV=production
    CommonsChunk + HashedModuleIdsPlugin()
    Transpile less code
    babel-preset-env + modules:false
    Browserlist
    useBuiltIns: true
    Scope Hoisting:
    Webpack 3
    RollUp
    Strip unused Lodash modules
    lodash-webpack-plugin
    babel-plugin-lodash
    Fewer Moment.js locales
    ContextReplacementPlugin()

    View Slide

  45. View Slide

  46. Pinterest’s old Mobile Site - 1st load
    First Paint: 4.2s
    First Meaningful Paint: 6.2s
    Time To Interactive: 23s

    View Slide

  47. Pinterest’s new Mobile Site - 1st load
    First Paint: 1.8s
    First Meaningful Paint: 5.1s
    Time To Interactive: 5.6s
    JS Bundles: 620KB ➡ 150KB
    CSS Bundles: 150KB ➡ 6KB inline
    P90 for Pin pages: 20s ➡ 6.5s

    View Slide

  48. Webpack Bundle Analyzer: Before splitting out common async route code

    View Slide

  49. Webpack Bundle Analyzer: After moving out common code from async chunks into entryChunk
    60-90% decrease in size of async route chunks (e.g 13.9KB ➡ 1KB)
    20% increase in size of entry (59KB ➡ 71KB)

    View Slide

  50. INTRODUCE WORKFLOWS THAT
    FORCE EVERYBODY TO THINK
    ABOUT LOADING TIMES FROM
    THE BEGINNING.
    n

    View Slide

  51. View Slide

  52. Performance Budgets for JS
    Budgets Tinder tries not to exceed
    Vendor
    Async
    Other
    155KB
    55KB
    35KB
    CSS 20KB

    View Slide

  53. import A from '../A';

    import B from '../B';

    const route = [

    {

    route: '/',

    regions: {

    side: A,

    main: B

    }

    }

    ];
    JavaScript Route-based code-splitting
    Before
    main.js
    A B

    View Slide

  54. import Loadable from ‘react-loadable';

    const A = Loadable({

    loader: () => import('../A' /* webpackChunkName: "pc-r-A" */),

    loading: () => null

    });

    const B = Loadable({

    loader: () => import('../B' /* webpackChunkName: "pc-r-B" */),

    loading: () => null

    });


    const route = [

    {

    route: '/',

    regions: {

    side: A,

    main: B

    },

    preload: [ /* next page chunk to preload*/ ]

    }
    React Loadable
    CommonsChunkPlugin
    After
    A.js
    B.js

    View Slide

  55. JavaScript Route-based code-splitting + budgets
    Before
    Main bundle size: 166kb
    DOMContentLoad: 5.46s
    load: 11.91s
    After
    Main bundle size: 101kb
    DOMContentLoad: 4.69s
    load: 4.69s

    View Slide

  56. CACHING

    View Slide

  57. * Chrome has 4+ caches. The above reflects the main two - the HTTP and memory caches
    Chrome’s Cache Hit Rates

    View Slide

  58. Cache-Control Policies
    /page
    HTML
    /style.3da37df.css
    CSS
    /script.8sd34ff.js
    JavaScript
    /photo.jpg
    Image
    Cache-Control: max-age=31536000
    Cache-Control: no-cache
    Cache-Control: private, max-age=31536000
    Cache-Control: max-age=86400
    https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching

    View Slide

  59. HTTP Caching Checklist
    Use consistent URLs and minimize resource churn
    Provide a validation token (ETag) to avoid transferring unchanged bytes
    Identify resources that can be cached by intermediaries (like CDNs)
    Determine the optimal cache lifetime of resources (max-age)
    Consider a Service Worker for more control over your repeat visit caching
    1.
    2.
    3.
    4.
    5.
    bit.ly/caching-checklist

    View Slide

  60. View Slide

  61. Before Service Worker After Service Worker

    View Slide

  62. https://jakearchibald.com/2016/caching-best-practices/

    View Slide

  63. PRIORITY

    View Slide

  64. http://beta.httparchive.org
    Using Dev Tools mobile emulation, Moto G4 calibrated CPU, Cable (5/1mbps, 28ms)
    TIME TO INTERACTIVE ON MOBILE
    35s 22s 14s
    10% sites 25% sites 50% sites

    View Slide

  65. View Slide

  66. View Slide

  67. View Slide

  68. View Slide

  69. View Slide


  70. Chrome 50 Safari 11 Firefox WIP

    View Slide


  71. 
<br/>(async () => {
<br/>try {
<br/>const response = await fetch(new Request("movies.json", {credentials: "include"}));
<br/>const data = await response.json();
<br/>console.log(data);
<br/>} catch (exception) {
<br/>console.log("Booo");
<br/>}
<br/>})();
<br/>
    I have critical resources I want to load earlier than discovery.
    Chrome 62

    View Slide

  72. How are sites are using link rel=preload?
    BBC News - Stylesheets

    View Slide

  73. BBC News - using for their stylesheets

    View Slide

  74. 36% improvement

    View Slide

  75. before
    after Reduce first paint by 500ms, load time by 1 second

    View Slide

  76. ~1s saving

    View Slide

  77. View Slide

  78. Link element
    Link header

    View Slide

  79. View Slide

  80. View Slide

  81. Express + HTTP/2 Push Headers
    const express = require('express'),
    let app = express();
    app
    .use('/js', express.static('js'))
    .get('/', function (req, res) {
    res.set('Link', `
    ; rel=preload; as='style',
    ; rel=preload; as='script',
    ; rel=preload; as='script'`)

    View Slide

  82. shop.polymer-project.org

    View Slide

  83. HTTP/2 with 3G
    ~8s

    View Slide

  84. <5s

    View Slide

  85. HTTP/2 SERVER PUSH, BASICALLY
    REMY

    View Slide

  86. View Slide

  87. View Slide

  88. View Slide

  89. https://jakearchibald.com/2017/h2-push-tougher-than-i-thought/

    View Slide

  90. AUTOMATE
    https://github.com/addyosmani/critical
    INLINE CRITICAL CSS
    Critical - extract & inline critical CSS
    using Chrome Headless

    <br/>/* critical */<br/>

    <br/>/* loadCSS */<br/>
    inline async

    View Slide

  91. Baseline
    Critical CSS
    Preload
    H/2 Push
    https://speakerdeck.com/patrickhamann/css-and-the-first-meaningful-paint-css-conf-eu-may-2017

    View Slide

  92. PAGE WEIGHT

    View Slide

  93. http://beta.httparchive.org
    Using Dev Tools mobile emulation, Moto G4 calibrated CPU, Cable (5/1mbps, 28ms)
    WEB PAGE WEIGHT ON MOBILE
    5.4MB 2.9MB 1.4MB
    10% sites 25% sites 50% sites

    View Slide

  94. How many sites do not serve content
    compressed?
    ~30%

    View Slide

  95. GZIP, BROTLI, ZOPFLI
    Compress!

    View Slide

  96. Apache
    NGINX
    gzip on;
    gzip_vary on;
    gzip_comp_level 6;
    gzip_http_version 1.1;
    gzip_proxied any;
    gzip_min_length 256;
    gzip_buffers 16 8k;
    gzip_types text/plain text/html text/css
    application/x-javascript text/xml
    application/xml application/xml+rss
    text/javascript;
    AddOutputFilterByType DEFLATE text/plain
    AddOutputFilterByType DEFLATE text/html
    AddOutputFilterByType DEFLATE text/xml
    AddOutputFilterByType DEFLATE text/css
    AddOutputFilterByType DEFLATE application/xml
    AddOutputFilterByType DEFLATE application/xhtml+xml
    AddOutputFilterByType DEFLATE application/rss+xml
    AddOutputFilterByType DEFLATE application/javascript
    AddOutputFilterByType DEFLATE application/x-javascript
    .htaccess
    nginx.conf

    View Slide

  97. View Slide

  98. Brotli
    Improved load time by 7% in India & 4% U.S
    bit.ly/linkedin-brotli
    Decreased the size of static assets by 20%
    bit.ly/dropbox-brotli
    17% improvement for largest JS bundles
    bit.ly/certsimple-brotli
    1.5 petabytes (million gigs) saved a day
    bit.ly/playstore-brotli

    View Slide

  99. Brotli Use: Mostly JavaScript, CSS and HTML
    From “Tracking the performance of the web with HTTP Archive”

    View Slide

  100. Remove unnecessary downloads
    The fastest and best-optimized resource is a resource not sent.
    Inventory your own assets and third-party assets on your pages.
    Measure the perf of each asset: its value and its technical performance.
    Determine if the resources are providing sufficient value.
    Lazy-load/defer resources that are non-critical as much as possible.
    1.
    2.
    3.
    4.
    5.

    View Slide

  101. WEB FONTS

    View Slide

  102. http://beta.httparchive.org
    Using Dev Tools mobile emulation, Moto G4 calibrated CPU, Cable (5/1mbps, 28ms)
    WEB FONT WEIGHT ON MOBILE
    200KB 100KB 80KB
    10% sites 25% sites 50% sites

    View Slide

  103. View Slide

  104. View Slide

  105. https://meowni.ca/font-style-matcher/

    View Slide

  106. https://www.zachleat.com/web/comprehensive-webfonts/
    “Comprehensive
    Web Fonts”

    View Slide

  107. @font-face {

    font-family: 'Roboto';

    font-display: optional;

    src: url(Roboto.woff) format('woff'),

    url(Roboto.eot) format('eot');

    font-weight: 400;

    font-style: normal;

    }
    If my Web Fonts can’t load quickly, don’t load them at all.
    Chrome 60 Safari WIP Firefox WIP

    View Slide

  108. View Slide


  109. View Slide

  110. Heaviest use of rel=preload is for Web Fonts
    HTTPArchive

    View Slide

  111. Preloading Web Fonts = 50% (1.2s)
    improvement in time-to-text-paint

    View Slide

  112. Use System Fonts when you can
    The fastest font is one that doesn’t need to load.
    Try font-display: optional;
    If a Web Font can’t load fast, load a fallback instead. If the Web Font is
    cached, it’ll get used the next time the user loads the page.
    Try to request Web Fonts with a higher priority
    If Web Fonts are a critical to your UX, preload them to minimize FOIT.
    Try subsetting to limit the range of Web Font characters needed
    Subsetting removes characters & Open-Type features from fonts, reducing
    file size. Google Fonts, TypeKit & Font Squirrel support it. Be careful with use.
    Try the CSS Font Loading API if you need more control
    Track font download progress & apply once fetched, manipulate font faces
    and override default lazy load behavior.
    S
    Have a Web Font Loading Strategy
    @addyosmani

    View Slide

  113. IMAGES

    View Slide

  114. http://beta.httparchive.org
    Using Dev Tools mobile emulation, Moto G4 calibrated CPU, Cable (5/1mbps, 28ms)
    IMAGE WEIGHT ON MOBILE
    3.9MB 1.9MB 0.8MB
    10% sites 25% sites 50% sites

    View Slide

  115. Image Quality Matters
    q=80 is a good baseline for web

    View Slide

  116. JPEG Encoders

    View Slide

  117. https://imageoptim.com
    www.xnview.com/en/xnconvert/

    View Slide

  118. Adapt intelligently
    H
    E
    I
    G
    H
    T
    Size appropriately
    WIDTH
    IMAGE DECODE
    Compress carefully Take care with tools
    Prioritize critical images
    HIGH
    LOW
    Lazy-load the rest
    Choose the right format
    Image
    Optimisation

    View Slide

  119. View Slide

  120. View Slide

  121. Heavy image decode
    Lower image decode

    View Slide

  122. Data Saver Mode introduced up to 70% savings for Twitter Lite
    Do this with the browser using the Save-Data client hint

    View Slide

  123. ESSENTIAL IMAGE OPTIMIZATION BOOK
    https://images.guide

    View Slide

  124. STAGE 3: MONITOR
    REMY

    View Slide

  125. EVERYONE IS
    RESPONSIBLE FOR
    performance.

    View Slide

  126. 5s

    View Slide

  127. View Slide

  128. View Slide

  129. Performance Budget Tools
    CALIBRE BUNDLESIZE
    SPEEDCURVE

    View Slide

  130. bit.ly/perf-budgets
    REAL-WORLD WEB PERF BUDGETS

    View Slide

  131. PERFORMANCE IS A JOURNEY.
    LOTS OF SMALL CHANGES
    CAN LEAD TO BIG GAINS.
    n

    View Slide

  132. KEEP RACING TOWARDS BETTER PERF
    REMY

    View Slide

  133. Thank you

    View Slide