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

96270e4c3e5e9806cf7245475c00b275?s=128

Addy Osmani

May 12, 2018
Tweet

Transcript

  1. Addy Osmani Ewa Gasperowicz Web Performance Made Easy

  2. What makes a web page feel heavy? 1.5MB 800KB Images

    350KB JavaScript 15s to load & get interactive HTTP Archive
  3. Lean and yet full of content

  4. Why does performance matter?

  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
  6. “Send less stuff!”

  7. Paul Irish in your pocket.

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

  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
  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
  11. Google Doodles google.com/doodles

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

  14. Lighthouse. 23 score 15s TTI

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

  16. Minify and compress JavaScript and CSS const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

    const webpackConfig = { plugins: [ new UglifyJsPlugin({...}) ] } Before After $ firebase deploy
  17. 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
  18. 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
  19. JS and CSS Code Unused Scripts with unused code slowing

    page load CHALLENGE
  20. Unused code can surprise us Doodle: Halloween 2016

  21. Check Code Coverage 95% unused

  22. 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
  23. Sanity check: Perf is up, how about UX? Before After

  24. Did we miss anything? One component was using MDC. We

    can manually copy/paste the lines needed to fix.
  25. 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.
  26. Bloa CHALLENGE More crap Crap Useful content A “modern” web

    page d e WebPages t
  27. Detect enormous network payloads 3.2MB payload

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

    Express
  29. JavaScript Bundle Auditing `unicode` is 1.6MB parsed JS import-cost for

    Visual Code npm run build --report BundlePhobia Webpack Bundle Analyzer
  30. Auditing JavaScript bundles paid off. Before After Bonus: Saved another

    320KB discovering an unused dependency! 2.1MB saved 65% smaller
  31. 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.
  32. JavaScript Boot-up Time Is High CHALLENGE Video: Kevin Schaaf

  33. Credit: Susie Lu

  34. 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
  35. Use JavaScript Code-splitting Split by route Split by component

  36. 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
  37. 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
  38. None
  39. Unoptimized Images Images that are large, inefficient or unnecessary CHALLENGE

  40. Lighthouse Image Audits

  41. ImageOptim (Mac) XNConvert (Cross-platform) Build Process Roll your own CDN

    imagemin libvips Thumbor ImageFlow GUI CDN Cloudinary Imgix Fastly Akamai Image Optimization Tools
  42. After Optimize Images Lighthouse is happy too Before Optimize Images

    Properly size images Serve images in next-gen formats 1.21 mB 100 kB
  43. <img src="animation-30s.gif"> Animated GIFs can be expensive

  44. <img src="animation.gif"> 7.3MB 960KB 1.3MB <video autoplay muted playsinline> <source

    src="video.webm" type="video/webm"> <source src="video.mp4" type="video/mp4"> </video> 80%+ savings Replace Animated GIFs with <video> ffmpeg -i animation.gif -b:v 0 -crf 40 -vf scale=600:-1 video.mp4
  45. 4G+ get <video> 2G-3G get static <img> ~1MB ~30KB Adapt

    based on user’s effective network connection navigator.connection.effectiveType
  46. Doodle Slider Carousels often load unnecessary images

  47. LazySizes import lazysizes from 'lazysizes' <script src="lazysizes.min.js"></script> <!-- non-responsive: -->

    <img data-src="image.jpg" class="lazyload"/> <!-- responsive: --> <img 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
  48. Solution • Optimize images • Use responsive Images ◦ <img

    srcset>, <picture> ◦ 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.
  49. https://images.guide Image Optimisation Book

  50. Resources Discovered & Delivered Late PROBLEM

  51. Let the browser know what’s important to fetch. Doodle: Celebrating

    50 years of kids coding <link rel=preconnect> <link rel=preload> <link rel=prefetch>
  52. <link rel="preconnect" href="https://fonts.googleapis.com/" crossorigin> <link rel="preconnect" href="https://fonts.gstatic.com/"crossorigin> 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
  53. ▾ 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 <link rel="preload" as="font" href="webfont.woff2" type="font/woff2" crossorigin="anonymous"> Web Fonts
  54. Web Fonts: with and without <link rel=preload> 1s saved Diagram

    is for illustrative purposes only
  55. Self-host Web Fonts for maximum control Pros <link rel=preload> 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
  56. Solution • Connecting to critical origins? ◦ <link rel=preconnect> •

    Asset for current page? ◦ <link rel=preload> ◦ preload-webpack-plugin • Asset for future navigation? ◦ <link rel=prefetch> ◦ 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.
  57. <link rel="preload" as="script" href="critical-script.js"> <link rel="preload" as="style" href="theme.css" importance="low" onload="this.rel=stylesheet">

    <style>/* critical-path styles */</style> <img src="hero.jpg" importance="high"> <img src="meme.gif" importance="low"> <!-- superfluous fetch requests --> <script> fetch('/api/related.json', { importance: 'low' }); </script> <!-- scripts at the end of the document --> <script src="critical-script.js"></script> Experimental Feature: Priority Hints github.com/WICG/priority-hints
  58. Image Carousel Browser prioritized images Image Carousel Fix using <img

    importance> Start images Middle images 2s saved
  59. Invisible Text While Web Fonts Load PROBLEM Request page Get

    HTML Get CSS Get Web Font Blocked text painting Render blocking A
  60. Flash of invisible text Fully loaded Web Font Avoid invisible

    text while Web Fonts are loading
  61. 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]
  62. font-display

  63. Solution • font-display: swap or optional • <link rel=preload> •

    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.
  64. Render-blocking Scripts External stylesheets block first paint of your page

    PROBLEM
  65. Perceived performance could be improved External stylesheets impacted our metrics

    Reduce render-blocking stylesheets opportunity
  66. Critical path optimisation Tools Critical Penthouse loadCSS <head> <style>/* Inlined

    critical styles */</style> <link href="app.css" rel="preload" as="style" onload="this.onload=null;this.rel='stylesheet'"> </head> <body> <div id="app"> <!-- AppShell markup --> </div> <noscript> <link href="app.css" rel="stylesheet"> </noscript> </body>
  67. Critical path optimisation Before After 1.2s saved on FMP +

    TTI
  68. Solution • Inline critical styles in <head> 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.
  69. Doodle: Tu Be'av 2017 Video of final loading vs initial

    speed
  70. None
  71. github.com/google/oodle-demo

  72. The final score 2.6s TTI

  73. Case Study Nikkei

  74. 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
  75. • • • • • • • • • •

    • Nikkei - Optimizations 43% smaller JS bundles 75% faster loading w/prefetch 94% cache-hit ratio
  76. Nikkei - Critical-path CSS optimizations Before After 1s faster FMP

  77. PRPL Pattern

  78. Machine Learning + Web Performance One More Thing

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

  80. Predict Page Navigations predictjs.firebaseapp.com

  81. Data-driven Loading for Web Sites Prefetch next pages a user

    is likely to visit as they browse. <link rel=prefetch> Analyze User Navigations Page Previous Page Path Page Views Exits Metrics Model Next Page Predictions (Markov Chains, Neural Networks, TensorFlow)
  82. 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
  83. alpha github.com/guess-js

  84. 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.
  85. None
  86. 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
  87. 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.
  88. We want to hear from you! Provide feedback for this

    session by signing in on google.com/io/schedule