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

Web Performance Made Easy

Web Performance Made Easy

The web has made great progress in enabling fast experiences, but building a fast site today isn’t trivial. At Google, we analyze a lot of sites and have learned what makes them load quickly and run smoothly. In this talk, learn how to find and fix the most common web performance bottlenecks to improve your UX by using tools like Lighthouse and DevTools, and discover the latest browser APIs to get more control over your loading experience.

Video: https://www.youtube.com/watch?v=Mv-l3-tJgGk

Addy Osmani

May 12, 2018
Tweet

More Decks by Addy Osmani

Other Decks in Technology

Transcript

  1. Addy Osmani Ewa Gasperowicz
    Web Performance
    Made Easy

    View full-size slide

  2. What makes a web page
    feel heavy?
    1.5MB
    800KB
    Images
    350KB
    JavaScript
    15s to load & get interactive
    HTTP Archive

    View full-size slide

  3. Lean
    and yet
    full of content

    View full-size slide

  4. Why does
    performance matter?

    View full-size slide

  5. How important is speed to users?
    Speed Matters, Vol. 3
    24% How attractive the site looks
    58% How simple the site is to use
    61% How well the site fits my screen
    66% How easy it is to find what I’m looking for
    75% The speed it takes to load the page
    UX HIERARCHY

    View full-size slide

  6. “Send less stuff!”

    View full-size slide

  7. Paul Irish in your
    pocket.

    View full-size slide

  8. New Lighthouse Web Performance Audits
    bit.ly/lighthouse-perf

    View full-size slide

  9. JavaScript Boot-up Time
    Preload key requests
    Avoid multiple, costly round trips to any origin (preconnect)
    Use a video format for animated content (instead of GIF)
    Main thread work breakdown
    Unminified JavaScript & CSS
    Unused CSS rules
    All text remains visible during webfont loads
    Uses efficient cache policy on static assets
    New Lighthouse Audits
    New Lighthouse Audits

    View full-size slide

  10. Fixing web performance is as easy as drawing a horse
    Van Oktorp (insp)
    1. Draw 2 circles 2. Draw the legs 3. Draw the face 4. Draw the HAIR 5. Add small details

    View full-size slide

  11. Google Doodles
    google.com/doodles

    View full-size slide

  12. Let’s start our journey.
    Doodle: Pony Express

    View full-size slide

  13. Lighthouse.
    23
    score
    15s
    TTI

    View full-size slide

  14. Unnecessary resources
    Send less stuff and fewer bytes
    CHALLENGE
    vs.

    View full-size slide

  15. Minify and compress JavaScript and CSS
    const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
    const webpackConfig = { plugins: [ new UglifyJsPlugin({...}) ] }
    Before
    After
    $ firebase deploy

    View full-size slide

  16. Inefficient cache policies
    Firebase.json:
    "source": "**/*.@(jpg|jpeg|gif|png|woff2)",
    "headers": [{
    "key": "Cache-Control",
    "value": "max-age=31536000"
    }]
    Short cache lifetimes can impact repeat visits
    After

    View full-size slide

  17. Solution
    ● Minimize code
    ● Automate minification
    ○ UglifyJS
    ○ Cloudflare
    ○ mod_pagespeed
    ● Compress (gzip, brotli)
    ● Cache wherever possible
    Review the legal playbook to learn how to source imagery,
    amongst other important legal guidelines:
    go/iospeakerplaybook.
    For every image used in the deck, add source details in the
    “For Legal Review” slide.
    Remove
    unnecessary
    bytes and don’t
    send things
    twice

    View full-size slide

  18. JS and CSS Code Unused
    Scripts with unused code slowing page load
    CHALLENGE

    View full-size slide

  19. Unused code
    can surprise us
    Doodle: Halloween 2016

    View full-size slide

  20. Check Code Coverage
    95%
    unused

    View full-size slide

  21. If we drop MVC adapter our styles drop to 10KB!
    Vue MDC Adapter
    We have almost no unused CSS now
    194 kB 9.8 kB

    View full-size slide

  22. Sanity check: Perf is up, how about UX?
    Before After

    View full-size slide

  23. Did we miss anything? One component was using MDC.
    We can manually copy/paste the lines needed to fix.

    View full-size slide

  24. Solution
    ● Code Coverage in DevTools
    ○ Page load
    ○ Runtime
    ● Lighthouse Coverage Audit
    ● Remove unused code to
    improve page load time
    ● Test for regressions
    Review the legal playbook to learn how to source imagery,
    amongst other important legal guidelines:
    go/iospeakerplaybook.
    For every image used in the deck, add source details in the
    “For Legal Review” slide.
    Remove unused
    JavaScript &
    CSS from the
    critical path.

    View full-size slide

  25. Bloa
    CHALLENGE
    More
    crap
    Crap Useful content
    A “modern” web page
    d
    e WebPages
    t

    View full-size slide

  26. Detect enormous network payloads
    3.2MB
    payload

    View full-size slide

  27. The fastest
    request is
    the one not
    made.
    Doodle: Pony Express

    View full-size slide

  28. JavaScript Bundle Auditing
    `unicode` is 1.6MB parsed JS
    import-cost for Visual Code
    npm run build --report
    BundlePhobia
    Webpack Bundle Analyzer

    View full-size slide

  29. Auditing JavaScript bundles paid off.
    Before
    After
    Bonus: Saved another 320KB discovering an unused dependency!
    2.1MB
    saved
    65%
    smaller

    View full-size slide

  30. Solution
    ● Make an inventory of all assets
    ● Measure value & impact of assets
    ● Audit your assets regularly
    Review the legal playbook to learn how to source imagery,
    amongst other important legal guidelines:
    go/iospeakerplaybook.
    For every image used in the deck, add source details in the
    “For Legal Review” slide.
    Eliminate
    unnecessary
    downloads.

    View full-size slide

  31. JavaScript Boot-up Time Is High
    CHALLENGE
    Video: Kevin Schaaf

    View full-size slide

  32. Credit: Susie Lu

    View full-size slide

  33. JavaScript Boot-up time is high
    import DoodleHome from './DoodleHome'
    import DoodleBrowse from './DoodleBrowse'
    import DoodleFullscreen from './DoodleFullscreen'
    import DoodleOffline from './DoodleOffline'
    Before code-splitting (static import)
    1.8s
    boot-up

    View full-size slide

  34. Use JavaScript Code-splitting
    Split by route
    Split by component

    View full-size slide

  35. Code-splitting reduced JavaScript Boot-up Time
    const DoodleHome = () => import('./DoodleHome')
    const DoodleBrowse = () => import('./DoodleBrowse')
    const DoodleFullscreen = () => import('./DoodleFullscreen')
    const DoodleOffline = () => import('./DoodleOffline')
    After code-splitting (dynamic import) 0.78s
    boot-up
    56%
    faster

    View full-size slide

  36. Solution
    ● Only send code users need.
    ● Use code-splitting
    ○ Split routes
    ○ Split components
    ○ Split vendor bundles
    ● Consider tree-shaking
    ● Serve modern, smaller JS bundles
    to modern browsers
    ● Remove unused library code with
    bit.ly/webpack-libs
    Review the legal playbook to learn how to source imagery,
    amongst other important legal guidelines:
    go/iospeakerplaybook.
    For every image used in the deck, add source details in the
    “For Legal Review” slide.
    Fast JS = fast at
    Download
    Parse
    Compile
    Execute

    View full-size slide

  37. Unoptimized Images
    Images that are large, inefficient or unnecessary
    CHALLENGE

    View full-size slide

  38. Lighthouse Image Audits

    View full-size slide

  39. ImageOptim (Mac)
    XNConvert (Cross-platform)
    Build Process
    Roll your own CDN
    imagemin
    libvips
    Thumbor
    ImageFlow
    GUI
    CDN
    Cloudinary
    Imgix
    Fastly
    Akamai
    Image Optimization Tools

    View full-size slide

  40. After
    Optimize Images
    Lighthouse is happy too
    Before
    Optimize Images
    Properly size images
    Serve images in next-gen formats
    1.21 mB 100 kB

    View full-size slide


  41. Animated GIFs can be expensive

    View full-size slide

  42. 7.3MB
    960KB
    1.3MB




    80%+ savings
    Replace Animated GIFs with
    ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4

    View full-size slide

  43. 4G+ get 2G-3G get static
    ~1MB ~30KB
    Adapt based on user’s effective network connection
    navigator.connection.effectiveType

    View full-size slide

  44. Doodle Slider
    Carousels often load unnecessary images

    View full-size slide

  45. LazySizes
    import lazysizes from 'lazysizes'


    class="lazyload"/>

    data-sizes="auto"
    data-src="image2.jpg"
    data-srcset="image1.jpg 300w,
    image2.jpg 600w,
    image3.jpg 900w"/>
    1. Include library
    2. Use

    View full-size slide

  46. Solution
    ● Optimize images
    ● Use responsive Images
    ○ ,
    ○ Media Queries
    ○ Client-hints
    ● Use lighter formats (SVG, video)
    ● Lazy-load offscreen images
    Review the legal playbook to learn how to source imagery,
    amongst other important legal guidelines:
    go/iospeakerplaybook.
    For every image used in the deck, add source details in the
    “For Legal Review” slide.
    Don’t serve
    unoptimized or
    unnecessary
    images to your
    users.

    View full-size slide

  47. https://images.guide
    Image Optimisation Book

    View full-size slide

  48. Resources Discovered & Delivered Late
    PROBLEM

    View full-size slide

  49. Let the browser
    know what’s
    important to
    fetch.
    Doodle: Celebrating 50 years of kids coding



    View full-size slide



  50. Mask connection latency with rel=preconnect
    ▾ Avoid multiple, costly round trips to any origin 300 ms
    Google Fonts stylesheets + Web Fonts
    Origin Potential Savings
    https://fonts.googleapis.com 300 ms
    https://fonts.gstatic.com 300 ms
    Avoid multiple, costly round trips to any origin
    0.3s
    faster

    View full-size slide

  51. ▾ Preload key requests
    URL Potential Savings
    ../Montserrat.woff2 (fonts.gstatic.com) 790 ms
    ../Teko.woff2 (fonts.gstatic.com) 800 ms
    Preload key requests
    800 ms
    type="font/woff2" crossorigin="anonymous">
    Web Fonts

    View full-size slide

  52. Web Fonts: with and without
    1s
    saved
    Diagram is for illustrative purposes only

    View full-size slide

  53. Self-host Web Fonts for maximum control
    Pros

    font-display
    unicode-range
    Easier subsetting
    Cons
    Lose Google Fonts cache-hit rate
    Lose Google Fonts server optimizations
    Have to check for updates
    google-webfonts-helper
    url('https://fonts.gstatic.com/s/montserrat/v12/JTUSjIg1_i6t8kCHKm 459WRhyyTh89ZNpQ.woff2') format('woff2');
    Works around Google Fonts URLs expiring or changing

    View full-size slide

  54. Solution
    ● Connecting to critical origins?

    ● Asset for current page?

    ○ preload-webpack-plugin
    ● Asset for future navigation?

    ○ webpack 4.6 (prefetch, preload)
    Review the legal playbook to learn how to source imagery,
    amongst other important legal guidelines:
    go/iospeakerplaybook.
    For every image used in the deck, add source details in the
    “For Legal Review” slide.
    Help browsers
    deliver critical
    resources early.

    View full-size slide



  55. /* critical-path styles */



    <br/>fetch('/api/related.json', { importance: 'low' });<br/>


    Experimental Feature: Priority Hints
    github.com/WICG/priority-hints

    View full-size slide

  56. Image Carousel
    Browser prioritized images
    Image Carousel
    Fix using
    Start images Middle images 2s
    saved

    View full-size slide

  57. Invisible Text While Web Fonts Load
    PROBLEM
    Request page Get HTML Get CSS Get Web Font
    Blocked
    text painting
    Render
    blocking
    A

    View full-size slide

  58. Flash of invisible text Fully loaded Web Font
    Avoid invisible text while Web Fonts are loading

    View full-size slide

  59. font-display
    @font-face {
    font-family: 'Montserrat';
    font-style: normal;
    font-display: swap;
    font-weight: 400;
    src: local('Montserrat Regular'), local('Montserrat-Regular'),
    /* Chrome 26+, Opera 23+, Firefox 39+ */
    url('montserrat-v12-latin-regular.woff2') format('woff2'),
    /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
    url('montserrat-v12-latin-regular.woff') format('woff');
    }
    font-display: [swap | optional | block | fallback | auto]

    View full-size slide

  60. font-display

    View full-size slide

  61. Solution
    ● font-display: swap or optional

    ● Web Font subsetting
    ● Font Loading API
    ● Use SVGs instead of icon fonts
    ● For more, see Zach
    Leatherman’s Web Font recipes
    at bit.ly/webfont-recipes
    Review the legal playbook to learn how to source imagery,
    amongst other important legal guidelines:
    go/iospeakerplaybook.
    For every image used in the deck, add source details in the
    “For Legal Review” slide.
    Have a Web
    Font loading
    strategy.

    View full-size slide

  62. Render-blocking Scripts
    External stylesheets block first paint of your page
    PROBLEM

    View full-size slide

  63. Perceived performance
    could be improved
    External stylesheets impacted our metrics
    Reduce render-blocking stylesheets opportunity

    View full-size slide

  64. Critical path optimisation
    Tools
    Critical
    Penthouse
    loadCSS

    /* Inlined critical styles */
    onload="this.onload=null;this.rel='stylesheet'">






    rel="stylesheet">


    View full-size slide

  65. Critical path optimisation
    Before
    After
    1.2s saved on FMP + TTI

    View full-size slide

  66. Solution
    ● Inline critical styles in
    and preload/async load the rest
    ● Split styles into separate files
    organized by media query
    ● Mark non-critical scripts with
    the defer attribute or lazy-load
    Review the legal playbook to learn how to source imagery,
    amongst other important legal guidelines:
    go/iospeakerplaybook.
    For every image used in the deck, add source details in the
    “For Legal Review” slide.
    Reduce
    render-blocking
    scripts and
    stylesheets.

    View full-size slide

  67. Doodle: Tu Be'av 2017
    Video of final loading vs initial speed

    View full-size slide

  68. github.com/google/oodle-demo

    View full-size slide

  69. The final score
    2.6s
    TTI

    View full-size slide

  70. Case Study
    Nikkei

    View full-size slide

  71. Source: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis non erat sem
    +230% Organic traffic
    +58% Conversion rate
    +40% Daily active users
    +28% Page-views
    r.nikkei.com
    14s
    faster

    View full-size slide












  72. Nikkei - Optimizations
    43%
    smaller
    JS bundles
    75%
    faster loading
    w/prefetch
    94%
    cache-hit
    ratio

    View full-size slide

  73. Nikkei - Critical-path CSS optimizations
    Before
    After
    1s
    faster FMP

    View full-size slide

  74. PRPL Pattern

    View full-size slide

  75. Machine Learning +
    Web Performance
    One More Thing

    View full-size slide

  76. Data-driven User Experiences
    https://unsplash.com/photos/mcSDtbWXUZU

    View full-size slide

  77. Predict Page Navigations
    predictjs.firebaseapp.com

    View full-size slide

  78. Data-driven Loading for Web Sites
    Prefetch next pages a
    user is likely to visit as
    they browse.

    Analyze User
    Navigations
    Page
    Previous Page Path
    Page Views
    Exits Metrics
    Model Next Page
    Predictions
    (Markov Chains,
    Neural Networks,
    TensorFlow)

    View full-size slide

  79. Data-driven Bundling for Web Apps
    Prefetch next JavaScript
    chunks a user is likely to visit
    as they browse.
    Analyze User
    Navigations
    Page
    Previous Page Path
    Page Views
    Exits Metrics
    Model Next Page
    Predictions
    (Markov Chains,
    Neural Networks,
    TensorFlow)
    Map “Pages” to
    JavaScript router
    Bundle JavaScript
    routes into chunks

    View full-size slide

  80. alpha
    github.com/guess-js

    View full-size slide

  81. Guess.js: Predictive Fetching
    Analyze User
    Navigations
    Model Next Page
    Predictions
    (Markov Chains)
    Map “Pages” to
    JavaScript router
    Bundle JavaScript
    routes into chunks
    GA module Guess Parser Guess Webpack Plugin
    + Experimental support for predictive prefetching for static sites
    By Minko Gechev, Addy Osmani, Kyle Mathews & Katie Hempenius
    github.com/guess-js
    Prefetch next JavaScript
    chunks a user is likely to visit
    as they browse.

    View full-size slide

  82. Improving performance is a journey.
    Lots of small changes can lead to big gains.
    https://www.istockphoto.com/photo/girl-in-red-dress-with-money-gm476238192-65884907

    View full-size slide

  83. Thank you
    Addy Osmani
    Google
    developers.google.com/web/fundamentals/performance
    developers.google.com/web/tools/lighthouse
    Helpful resources
    Ewa Gasperowicz
    Google
    @addyosmani
    @devnook
    With special thanks to
    Ward Peeters, Minko Gechev, Kyle Mathews, Katie Hempenius, Dom
    Farolino, Yoav Weiss, Susie Lu, Yusuke Utsunomiya, Lighthouse &
    Google Doodles.

    View full-size slide

  84. We want to hear from you!
    Provide feedback for this session by signing in
    on google.com/io/schedule

    View full-size slide