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

Speed at Scale: Web Performance Tips and Tricks from the Trenches

Speed at Scale: Web Performance Tips and Tricks from the Trenches

Getting your site fast and keeping it fast can be a challenge at scale. Learn 15 tips and tricks that real, production sites use to get great scores on Lighthouse and improve core business metrics. Understand a spectrum of optimizations from latency optimization to JavaScript, preloading, prefetching, data-fetching, and more.

This talk is from Google I/O 2019: https://events.google.com/io/schedule/events/9888b5c4-33eb-42d7-97c8-4cef89f20b98

Addy Osmani

May 08, 2019
Tweet

More Decks by Addy Osmani

Other Decks in Programming

Transcript

  1. Speed at Scale
    WebPerf Tips & Tricks From The Trenches
    2019
    Google I/O
    Katie Hempenius
    @katiehempenius
    Addy Osmani
    @addyosmani

    View Slide

  2. View Slide

  3. addEventListener('')

    View Slide

  4. Interactivity impacts rage clicks
    Based on Akamai’s 2018 research into UX & Metrics that matter

    View Slide

  5. Page Weight Percentiles

    View Slide

  6. Sending too much to the browser

    View Slide

  7. Proprietary + Confidential
    Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem
    Delightful user experiences can be found everywhere

    View Slide

  8. Performance Budgets

    View Slide

  9. Cleaning up your
    site 6 months in

    View Slide

  10. 40% of brands regress
    on web performance
    after 6 months.
    Internal Google study into Web Performance investments by large brands.

    View Slide

  11. Performance budgets
    set standards for the
    performance of your
    site.

    View Slide

  12. Time
    < 2 second TTI
    KB KB
    Resources
    < 150KB JS
    Lighthouse
    90+ Perf Score

    View Slide

  13. Catch issues before they ship
    “Checking the size of our builds ensures
    that we don’t miss potential
    performance issues. For example, this
    has caught dependencies being added
    unnecessarily. Since the PR was blocked,
    we were able to pinpoint the issue and fix
    it before it impacted our build."
    “By setting a budget for tracking, and
    reporting build size deltas, we've prevented
    changes that would have increased
    metrics like TTI, TTFMC and Time to First
    Tweet by over 100%.”
    Paul Armstrong, Twitter
    Jeff McRiffey, Walmart eCommerce

    View Slide

  14. Job checks and logs
    the size of all builds.
    PRs fail if size
    increases by > 1%
    (main bundles only)
    Issues are escalated
    to a performance
    engineer.
    > node bundle-check.js
    +4.4% - discoveryJS
    +0.0% - discoveryCSS
    +0.0% - coreJS
    -0.0% - checkoutJS
    +0.0% - checkoutCSS

    View Slide

  15. Build tracker comments
    on PRs with a detailed
    breakdown of changes.
    Build tracker logs the size
    of all production builds.
    Engineers use this info
    when reviewing PRs.

    View Slide

  16. Performance budget tooling for Lighthouse
    bit.ly/lightwallet-docs
    LightWallet

    View Slide

  17. 1. Add a budget.json file
    2. Run Lighthouse 5.0+ from the CLI
    $ lighthouse https://example.com --budgetPath ./budget.json
    LightWallet bit.ly/lightwallet-docs

    View Slide

  18. LightWallet bit.ly/lightwallet-docs

    View Slide

  19. [{
    "resourceSizes": [
    {
    "resourceType": "image",
    "budget": 250
    },
    {
    "resourceType": "script",
    "budget": 125
    },
    {
    "resourceType": "font",
    "budget": 30
    },
    {
    "resourceType": "document",
    "budget": 25
    },
    {
    "resourceType": "stylesheet",
    "budget": 5
    },
    {
    "resourceType": "third-party",
    "budget": 400
    }
    ]
    }];
    budget.json
    Budget types:
    ● Resource Sizes
    ● Resource
    Counts

    View Slide

  20. 750KB
    3.5 MB
    JavaScript
    Other
    Time to Interactive of 3.9 million mobile sites
    Median: 8.9 seconds
    Data source: HTTP Archive

    View Slide

  21. f(JS
    KB,
    Non-JS
    KB
    ) →TTI
    bit.ly/perf-budget-calculator
    Performance
    Budget
    Calculator

    View Slide

  22. 4.1s
    Range:
    3.2-5.1s
    5.1s
    Range:
    4.1-6.4s
    6s
    Range:
    4.8-7.5s
    100 KB JS 200 KB JS 300 KB JS
    300 KB other
    300 KB other
    300 KB other
    bit.ly/perf-budget-calculator

    View Slide

  23. Image CDN
    Lazy-loading Responsive
    Images

    View Slide

  24. Lazy Loading

    View Slide

  25. Am I a joke to you?
    Data Plan
    5MB
    Images a page
    ~4.7MB images at P90 from HTTP Archive

    View Slide

  26. Lazy-load
    offscreen images
    Eager Loading
    Load images right away
    Lazy Loading
    Load (offscreen) images on-demand
    2MB 1MB
    Potential Savings
    3MB (P90) and 416KB (Median)

    View Slide



  27. Solid Color 1KB 13KB
    Progressive image loading
    LQIP (Low-quality placeholder)
    Lazy-loading images with JS
    Common

    View Slide

  28. Optimizing
    Chrome.com Faster page load times
    (mobile)
    20%
    Faster page load times
    (desktop - Windows)
    26%
    chrome.com
    Credits:
    Vitaly Keyzla (Dev Lead, Infra) Wei-Hsin Chen (Senior
    Eng/Lead) Luis Villalba (Senior Eng/Lead) Felipe Angel (Eng)
    Cristian Perez (QA) Katia Pena (QA Lead) Luis Jimenez
    (Director QA) Neil Shankar (UI Designer) Melissa Castano
    (Senior UI Designer) Esteban Lobo Guerrero (UI/UX
    Designer) McKenzy Germain (Web Product Manager) Kevin
    Furuichi (Android/Chrome Program Manager) Adam
    Dunlavey (Senior Web Analyst)

    View Slide

  29. Lazy-Load
    Offscreen Images
    Fewer Image Bytes Loaded
    Upfront
    46%
    Chrome.com lazy-loads offscreen
    images. They use an SVG placeholder
    with image dimensions to avoid
    reflow. Their custom JS lazy-loader
    leverages Intersection Observer.

    View Slide

  30. Lazy-load offscreen images Defer render until decode
    Before After
    Initial state Final state
    Or download if img.decode() unsupported

    View Slide

  31. View Preview Experience

    View Slide

  32. View Slide

  33. Page load from server Page load after auto-loading
    all rows

    View Slide

  34. Optimized
    CPU load, memory
    & network traffic
    Images
    4.4MB
    Images
    1.2MB
    Full Page Load Initial Page State
    ...leading to faster start
    times for video previews.
    DOM Nodes
    11,744
    Memory
    45MB
    DOM Nodes
    650
    Memory
    8MB
    bit.ly/netflix-previews

    View Slide

  35. 46%
    Image Byte Savings
    After switching to image lazy-loading
    72%
    94%
    76%
    90%
    78%

    View Slide

  36. View Slide

  37. Introducing
    native image
    lazy-loading!

    Eager Loading

    Lazy Loading

    2MB 1MB
    chrome://flags/#enable-lazy-image-loading

    View Slide

  38. Introducing
    native iframe
    lazy-loading!

    Eager Loading

    Lazy Loading

    3MB
    iframe
    0MB
    iframe
    chrome://flags/#enable-lazy-frame-loading

    View Slide

  39. bit.ly/native-lazyload

    View Slide






  40. <br/>if ('loading' in HTMLImageElement.prototype) {<br/>const images = document.querySelectorAll("img.lazyload");<br/>images.forEach(img => {<br/>img.src = img.dataset.src;<br/>});<br/>} else {<br/>// Dynamically load the lazysizes library<br/>let script = document.createElement("script");<br/>script.src = "/lazysizes.min.js";<br/>document.body.appendChild(script);<br/>}<br/>
    Cross-browser
    Image lazy-loading
    Feature Detection
    JS library fallback

    View Slide

  41. Responsive Images

    View Slide

  42. 101 KB 299 KB
    vs.
    Images for desktop & tablet can be
    ~2-4x larger than the mobile version.

    View Slide

  43. By width By density
    srcset="cat-1x.jpg 1x,
    cat-2x.jpg 2x,
    cat-3x.jpg 3x">
    srcset="cat-240.jpg 240w,
    cat-480.jpg 480w
    cat-960.jpg 960w>
    Responsive Images
    Width descriptor
    w ≈ px
    window.devicePixelRatio
    Defines the relationship between
    device pixels and CSS pixels for a
    particular device.

    View Slide

  44. Pixel density
    ● Limits image pixel density to <= 2x
    ● Exception: full-screen images
    where users can pinch zoom.
    33% decrease
    in image size
    1x 2x 3x
    Result:
    No distinguishable
    difference to the
    human eye.
    4x

    View Slide

  45. Images CDNs

    View Slide

  46. Successful image
    Optimizations

    View Slide

  47. Image CDN
    images
    fancy

    View Slide

  48. Popular Image CDNs
    Akamai Image Manager | Cloudinary | Imgix | Thumbor (self-hosted)
    ...cat.jpg?q=50&w=300&h=200
    Set quality level to 50 Resize to 300x200

    View Slide

  49. Image CDNs
    "We realized that maintaining an inhouse image
    optimization solution would be enough work
    for a dedicated team. By using an Image
    CDN, our engineers can focus on our core
    business while our users benefit from fast,
    good-looking images across all devices &
    networks."
    Tobias Baldauf, Trivago

    View Slide

  50. Image CDNs
    ● Auto quality
    ● Auto cropping
    ● WebP
    ● Color channel tuning
    Decrease in
    image size (KB)
    80%

    View Slide

  51. 40%
    50%
    40-60%
    71%
    80%
    Image Byte
    Savings
    After switching
    to an image CDN

    View Slide

  52. Code-Splitting
    Defer Third-Party
    Embeds
    Expensive
    Libraries
    JavaScript

    View Slide

  53. Defer Third-Party
    JavaScript & Embeds

    View Slide

  54. 57%
    Patrick Hulce, thirdpartyweb.today. Data from across top 4M sites.
    57%
    JavaScript execution time on
    the web is third-party code

    View Slide

  55. How’s your JavaScript diet going?
    Me:
    @StumberVideos

    View Slide

  56. Gareth Clubb
    Everyone wants ‘that tag’ on a page that
    will make the organisation money. It’s very
    important to get the right individuals in a
    room to educate, challenge and work
    together.
    Create a Performance Culture

    View Slide

  57. Third-party JS
    2s 5s
    bit.ly/telegraph-3p
    Defer
    <br/><script defer><br/>bit.ly/telegraph-3p<br/>“Our biggest improvement was<br/>deferring all JS, including our own”<br/>“...this didn’t skew analytics<br/>or advertising. Lighthouse Perf +47”<br/>Other optimizations<br/>1MB reduction 1st & 3p JS<br/>4s faster “first ad” loading<br/>6s faster Time-to-Interactive<br/>

    View Slide

  58. When load times decreased 71%,
    bounce rates decreased 31%
    Faster Page
    Load Times
    78%
    Decrease in
    Bounce Rates
    31%
    Mobile CVR
    Increase
    11%
    tui.se

    View Slide

  59. Before After
    Defer Google Tag Manager
    Custom Third-Party
    Replace A/B Testing Library
    50% Reduction domComplete 100KB JS shaved from homepage

    View Slide

  60. Loading third-party embeds eagerly has a cost
    Chrome.com’s Time to Interactive was 13.6s

    View Slide

  61. Lazy-load
    Third-Party Embeds
    Lighthouse Performance
    Score (27 to 96)
    +69
    chrome.com
    Reduction in Time to
    Interactive (13.6s to 3.1s)
    10s
    Smaller JavaScript Payload
    511KB
    Before
    After
    Eagerly load YouTube embeds on
    page load.
    Lazy-load YouTube embeds on user
    interaction.

    View Slide

  62. Remove expensive
    libraries

    View Slide

  63. Remove expensive libraries
    There are other options too:
    ● Deprecate
    ● Replace
    ● Defer
    ● Update
    moment.js
    Bootstrap
    jQuery

    View Slide

  64. lodash → lodash-es
    momentjs → date-fns
    fetch → fetch-unfetch
    async → async-es
    babel-preset-es2015 →babel-preset-env
    Replace expensive libraries
    The one function
    you care about
    Importing entire module

    View Slide

  65. Defer
    dependencies
    ● Tokopedia serves a “lite”
    version of their app to new
    users.
    ● Lite version uses Svelte;
    service workers precache
    their React app in the
    background.
    React Version Svelte Version
    vs
    320 KB 37 KB
    JavaScript required to render above-the-fold content

    View Slide

  66. lit-html, Preact, & Svelte

    View Slide

  67. Update
    dependencies Improvement in load time
    100ms
    Uplift in revenue per session
    0.7%
    ● Zalando noticed that an
    older React version was
    impacting load times.
    ● Updated from React 15.6.1
    to 16.2.0.

    View Slide

  68. Code-splitting
    & Component Loading
    Loading
    Render quickly
    Load minimal useful code
    Set user expectations
    Final state

    View Slide

  69. Download JS Execution
    Critical for slow
    networks
    Critical for devices
    with slow CPUs

    View Slide

  70. “If JavaScript doesn’t bring
    users joy, thank it and throw
    it away”
    Marie Kondo*
    * Probably

    View Slide

  71. shopping.google.com
    Above-the-fold-rendering
    Interactivity for initial view
    Additional Search features
    Optimize
    UI Interactivity
    JS
    JS
    JS
    Tested on a Moto G4 over 3G
    Time to Interactive
    4.5s
    Lighthouse
    Performance
    90

    View Slide

  72. JavaScript
    Code-splitting Smaller JavaScript bundle
    69%
    Faster Time-to-Interactive
    28%
    Reduction First-Input-Delay
    30%
    Walmart Grocery split up their JS bundles
    using granular code-splitting. They
    removed old / duplicate dependencies and
    cleaned up A/B test configs. Core bundles are
    cached with SWs for bytecode caching.
    grocery.walmart.com

    View Slide

  73. Twitter

    View Slide

  74. Route-based code-splitting

    50%
    36%

    18%
    *improvements from Twitter Lite traces, 2017.
    **This and other optimizations for Twitter Lite’s
    launch led to a 75% increase in tweets sent.
    Time to Interactive improvements

    View Slide

  75. Review what your tools output!
    Efficiently bundling i18n for 34 languages
    Each build included i18n
    strings invalidating file
    hashes across the app.
    Each deploy invalidated your
    cache. Service Worker had to
    redownload everything.
    Issue caused by the tools.
    Generated files of same
    size, but different hashes.

    View Slide

  76. Lazy-load
    Translation strings
    Reduction in overall bundle
    size
    30KB
    Saved loading Emoji picker
    on-demand
    50KB
    mobile.twitter.com
    Internationalization
    tooling improvements
    Faster JS exec from
    new i18n pipeline
    80%

    View Slide

  77. JavaScript
    For first-time users
    Increase in
    day one plays
    54%
    mWeb users converted
    to native app installs
    30%
    This and other investments in the
    mobile web player led to...
    First time users trying to play
    a song get a fast sign-up
    55KB 300KB
    Once signed up, the mobile
    web player is lazy-loaded
    ~5s Time to Interactive on a Moto G4 over 4G

    View Slide

  78. Spotify improved perceived performance
    Reusing data from one page to hydrate next, reduced API calls & kept blank pages minimum
    Enables quick
    navigations
    between pages,
    even on slow
    connections.

    View Slide

  79. PRPL Pattern
    Interactive in 18KB JS
    Faster Time to
    Interactive
    82%
    This + other work
    Improvement
    in conversions
    25%
    Speed
    jabong.com
    Push minimal code to get interactive
    Render fast
    Precache other
    routes (SW)
    Lazy-load JS
    On demand
    HTML
    CSS
    JS
    JS
    JS
    JS

    View Slide

  80. Fonts

    View Slide

  81. Invisible Text
    By default, if a font is not loaded,
    the browser will hide text for up to:
    3 sec 3 sec 3 sec ∞
    Flash of
    Display font immediately

    View Slide

  82. Flash of invisible text Flash of unstyled text

    View Slide

  83. @font-face {
    font-family: 'Google Sans';
    src: url(...GoogleSans.woff2) format('woff2');
    font-display: swap;
    }
    Fonts
    chrome.com
    This & other techniques:
    Improvement in mobile
    page load times
    20%
    Improvement in “Visually
    Complete” on 3G
    .5s

    View Slide

  84. fonts.googleapis.com/css?family=Lobster
    &font-display=swap
    fonts.googleapis.com/css?family=Lobster
    &font-display=swap

    View Slide

  85. Get important vs meh
    resources first
    Why not both?
    Browser

    View Slide

  86. Decrease in
    Latency
    0.7s
    Preconnect
    Critical Origins
    .com
    Resource Hints
    Faster Time
    to Interactive
    1.5s
    Preload
    Critical Scripts
    Faster Time to Interactive
    For future pages
    2.7s
    Prefetch
    Visible Links
    bit.ly/quicklinkjs

    View Slide

  87. Prefetch
    Top Search Results
    Faster Median Above Fold Time
    (similar to FMP): 1.1s -> 0.39s
    759ms
    eBay prefetch the top 5 items in
    search results pages for fast
    subsequent loads. This happens during
    idle time with requestIdleCallback().
    “eBay saw a positive
    impact on conversions
    from prefetching”

    View Slide

  88. Predictive
    Asset Prefetching
    Home
    Search
    Item
    eBay are doing predictive prefetching
    of static assets. Home prefetches assets
    for Search. Search prefetches for Item
    page (and so on).
    Machine Learning & Analytics based
    prefetching us under consideration.

    View Slide

  89. Prefetch
    Popular Articles
    Faster article fetch time
    78%
    Article impressions
    +13% (after 1 week)
    +26% (after 2 weeks)
    Virgilio Sport prefetch articles based
    on analytics data. Service Workers and
    prefetch the most
    clicked posts for users not on 2G. SW
    updates the top articles every 7m.
    After 3 weeks
    45%
    Speed
    Prefetched

    View Slide

  90. Critical CSS

    View Slide

  91. Fold
    Inline critical CSS; deliver
    document in <= 14KB.
    Load CSS asynchronously.
    ● filamentgroup/loadcss
    ● addyosmani/critical
    ● filamentgroup/criticalcss
    ● pocketjoso/penthouse
    Critical CSS
    Other CSS

    View Slide

  92. 0s 1s 1.2s
    2.4s
    Improvement in FCP
    1.4s
    Critical CSS

    View Slide

  93. Determining
    Critical CSS
    Common factors:
    ● URL
    ● Device viewport
    Nikkei also dealt with these factors:
    ● Login state (logged in/out)
    ● Subscription (paying/free)
    ● Paywall (on/off)
    ● 300KB of “critical” CSS
    Challenge:

    View Slide

  94. Application
    Server
    Critical CSS
    Server
    User
    CSS
    Document with
    inlined CSS CDN
    Dynamic Critical CSS
    API returns critical CSS based on parameters like user state and page.
    ...?service=article

    View Slide

  95. User
    CSS
    Document with
    inlined CSS CDN
    Application
    Server
    Critical CSS
    Server
    Edge Side Inclusion (ESI)
    Caching
    Inlining ESI
    <br/>params<br/>Markup language for assembling documents; CDN feature.<br/>Example: <esi:include src="/critical.css?service=article"><br/>

    View Slide

  96. ● +58% conversions (subscriptions)
    ● +49% daily active users
    Dynamic Critical CSS
    Improvement in FCP
    1s
    Reduction in inlined CSS
    80%
    This & other
    techniques:
    (without ESI)
    ● 2x page views per session
    ● 2.3x organic traffic

    View Slide

  97. Brotli

    View Slide

  98. Brotli: Reduce bytes over the wire
    Compress
    JS & CSS
    JavaScript
    reduction
    15%
    Latency
    Improvement (P50)
    37%
    Decrease in payload
    size for P75 sized
    payloads
    90%
    Reduction globally for
    P95 load latencies.
    ~15-20% in Emerging
    Markets
    5%
    Compress API
    Responses

    View Slide

  99. Adaptive serving

    View Slide

  100. Before
    Adaptive Serving
    Adapt based on network quality & data signals
    After
    Reading news
    navigator.connection.effectiveType
    // 3g
    navigator.connection.saveData
    // true

    View Slide

  101. mBasic
    Site for low-end
    mTouch mBasic
    Time To Interactive
    1.6s
    mbasic.facebook.com
    m.facebook.com
    Facebook offer a basic version of
    their site for low-end devices. It
    has no JavaScript, very limited
    images and uses minimal CSS
    with tables mostly for layout.

    View Slide

  102. Data Saver
    Mode For Images Reduction for data-usage
    from images on web. 96%
    incl disabled video autoplay
    80%
    Twitter’s Data Saver mode presents
    images as a preview. The web renders
    a 64x64 blurred image (LQIP style).
    Users can tap to load large images.
    Previews load quick on 2G & 3G.
    Reduction for data-usage from
    images on iOS + Android
    50%

    View Slide

  103. Client-side compression of photo uploads
    Reduction in cancelled photo uploads
    ~9.5%
    On the server, compresses images to JPEG
    quality 85% & max dimensions of 4096x4096px.
    On the client, check if images appear above max
    dimensions or an MB limit. If so, draw to
    & output quality=85%.

    View Slide

  104. Adaptive
    Serving (Experiment)
    Before After
    eBay are experimenting with adaptive
    serving using effectiveType. On a fast
    connection, features like product
    zooming will load on demand. On slow
    connections, they won’t.

    View Slide

  105. View Slide

  106. 1. Lazy-loading
    2. Responsive Images
    3. Image CDNs
    4. Defer Third-party JS
    5. Remove costly libraries
    6. Code-Splitting
    7. Avoid FOIT
    8. Prefetch
    9. Preconnect
    10. Preload
    11. Critical CSS
    12. Brotli
    13. Adaptive Serving
    Get fast
    web.dev/fast
    Stay Fast
    bit.ly/lightwallet-docs
    Performance Budgets
    LightWallet

    View Slide

  107. Thank you!
    web.dev/fast
    bit.ly/lightwallet
    Helpful resources
    Katie Hempenius
    @katiehempenius
    Addy Osmani
    @addyosmani

    View Slide