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

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. What makes a web page feel heavy? 1.5MB 800KB Images

    350KB JavaScript 15s to load & get interactive HTTP Archive
  2. 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
  3. 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
  4. 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
  5. Minify and compress JavaScript and CSS const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

    const webpackConfig = { plugins: [ new UglifyJsPlugin({...}) ] } Before After $ firebase deploy
  6. 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
  7. 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
  8. 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
  9. Did we miss anything? One component was using MDC. We

    can manually copy/paste the lines needed to fix.
  10. 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.
  11. JavaScript Bundle Auditing `unicode` is 1.6MB parsed JS import-cost for

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

    320KB discovering an unused dependency! 2.1MB saved 65% smaller
  13. 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.
  14. 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
  15. 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
  16. 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
  17. ImageOptim (Mac) XNConvert (Cross-platform) Build Process Roll your own CDN

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

    Properly size images Serve images in next-gen formats 1.21 mB 100 kB
  19. <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
  20. 4G+ get <video> 2G-3G get static <img> ~1MB ~30KB Adapt

    based on user’s effective network connection navigator.connection.effectiveType
  21. 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
  22. 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.
  23. 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>
  24. <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
  25. ▾ 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
  26. 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
  27. 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.
  28. <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
  29. Image Carousel Browser prioritized images Image Carousel Fix using <img

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

    HTML Get CSS Get Web Font Blocked text painting Render blocking A
  31. 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]
  32. 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.
  33. 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>
  34. 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.
  35. 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
  36. • • • • • • • • • •

    • Nikkei - Optimizations 43% smaller JS bundles 75% faster loading w/prefetch 94% cache-hit ratio
  37. 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)
  38. 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
  39. 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.
  40. 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
  41. 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.
  42. We want to hear from you! Provide feedback for this

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