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

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. LOAD ONLY WHAT YOU NEED
    WHEN YOU NEED IT
    n

    View full-size slide

  2. 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 full-size slide

  3. User Expectations

    View full-size slide

  4. RESPONSE
    ANIMATION
    IDLE
    LOAD
    RAIL
    Evolving

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  7. Latencies are significantly higher than a wired connection

    View full-size slide

  8. Can we data-science
    the web?

    View full-size slide

  9. THIS CAN’T
    GO WRONG.

    View full-size slide

  10. NEW GAME
    OPTIONS
    A ROAD RASH RIFF

    View full-size slide

  11. PLAYER 1
    REMY
    LEVEL 1
    A TOTALLY SAFE ROAD

    View full-size slide

  12. STAGE 1: MEASURE
    REMY
    REMY

    View full-size slide

  13. 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 full-size slide

  14. Queryable RUM for
    the web?

    View full-size slide

  15. bit.ly/introducing-crux

    View full-size slide

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

    View full-size slide

  17. // 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 full-size slide

  18. RUM
    Chrome UX Report

    View full-size slide

  19. STAGE 2: OPTIMIZE
    REMY

    View full-size slide

  20. “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 full-size slide

  21. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  25. PRPL Pattern
    USED BY SITES LIKE
    SUPPORTED BY CLIs

    View full-size slide

  26. 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 full-size slide

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

    View full-size slide

  28. CODE COVERAGE

    View full-size slide

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

    View full-size slide

  30. LEARN FROM
    GAME DEVELOPERS

    View full-size slide

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

    View full-size slide

  32. 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 full-size slide

  33. 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 full-size slide

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

    View full-size slide

  35. 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 full-size slide

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

    View full-size slide

  37. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  40. 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 full-size slide

  41. 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 full-size slide

  42. 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 full-size slide

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

    View full-size slide

  44. 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 full-size slide

  45. 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 full-size slide

  46. Before Service Worker After Service Worker

    View full-size slide

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

    View full-size slide

  48. 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 full-size slide


  49. Chrome 50 Safari 11 Firefox WIP

    View full-size slide


  50. 
<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 full-size slide

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

    View full-size slide

  52. BBC News - using for their stylesheets

    View full-size slide

  53. 36% improvement

    View full-size slide

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

    View full-size slide

  55. Link element
    Link header

    View full-size slide

  56. 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 full-size slide

  57. shop.polymer-project.org

    View full-size slide

  58. HTTP/2 with 3G
    ~8s

    View full-size slide

  59. HTTP/2 SERVER PUSH, BASICALLY
    REMY

    View full-size slide

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

    View full-size slide

  61. 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 full-size slide

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

    View full-size slide

  63. 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 full-size slide

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

    View full-size slide

  65. GZIP, BROTLI, ZOPFLI
    Compress!

    View full-size slide

  66. 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 full-size slide

  67. 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 full-size slide

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

    View full-size slide

  69. 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 full-size slide

  70. 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 full-size slide

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

    View full-size slide

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

    View full-size slide

  73. @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 full-size slide

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

    View full-size slide

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

    View full-size slide

  76. 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 full-size slide

  77. 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 full-size slide

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

    View full-size slide

  79. JPEG Encoders

    View full-size slide

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

    View full-size slide

  81. 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 full-size slide

  82. Heavy image decode
    Lower image decode

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  85. STAGE 3: MONITOR
    REMY

    View full-size slide

  86. EVERYONE IS
    RESPONSIBLE FOR
    performance.

    View full-size slide

  87. Performance Budget Tools
    CALIBRE BUNDLESIZE
    SPEEDCURVE

    View full-size slide

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

    View full-size slide

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

    View full-size slide

  90. KEEP RACING TOWARDS BETTER PERF
    REMY

    View full-size slide