Skip to content

Instantly share code, notes, and snippets.

@john-bell-gw
Last active February 13, 2021 17:02
Show Gist options
  • Save john-bell-gw/2437cebb8d57df99a6ea2ddb1fcc692b to your computer and use it in GitHub Desktop.
Save john-bell-gw/2437cebb8d57df99a6ea2ddb1fcc692b to your computer and use it in GitHub Desktop.
My notes from Harry Robert's workshop on front-end performance

Front End Performance: Building Faster Websites

Harry Roberts

Slides from the workshop (Password: #perfmatters)

Desciption of the workshop from https://newadventuresconf.com/2019/workshops/harry-roberts/

Every case-study, every report, and every bit of feedback always tells us the same thing: speed matters. It’s good for users, it’s good for accessibility, and it’s good for business. But why are modern browsing experiences so slow? If technology is getting better, why are websites getting worse?

Useful Links

Case studies and experiments demonstrating the impact of web performance optimization (WPO) on user experience and business metrics.

The web isn't experienced the same way everywhere.

Performance is a feature. This book provides a hands-on overview of what every web developer needs to know about the various types of networks ... to deliver the best—fast, reliable, and resilient—user experience.

A set of Open Source tools that makes it easy to monitor and measure the performance of your web site.

My notes from the workshop

These are presented pretty much as I wrote them during the day. If something doesn't make sense, like it's missing some context, let me know and we can try to figure out what I was thinking when I wrote it.

Research

  • How do you know your site is slow?
  • What are the most valuable areas to optimize?
  • Simple page load time isn't that helpful. Users care how long it takes to see meaningful content.
  • Performance numbers coming out of Analytics aren't always accurate. Site speed isn't normalized / weighted for example.
  • Cloudinary / imagex - image providers which can deliver optimized images for you
  • Implement the User Timing API to send data to Analytics or NewRelic
  • Providing offline content - customer service information for example.
  • Use slowfil.es to simulate slow resources href="https://slowfil.es/file?type=css&delay=1000"
  • How do slow loading resources affect user experience. Can you design to mitigate this?
  • Percieved performance tricks. - Skeleton screens, loading spinners, placeholders, messages, fallbacks. Better than a blank screen.
  • Server Timings API - BBC iPlayer for example.
  • hpbn.co : a technical book about performance
  • The 3 Cs
  • cache-control-immutable
  • Image provider services - optimizing images for content admins. Wordpress and tout images!
  • HTTP2 / service workers
  • Priority hints - high | low | auto
<img src="reallyImportantImage.jpg" importance="high" />
  • If we provided offline fallback content, what would it be?

Implement

  • Dig around in Analytics and NewRelic, see what you find. Talk to Anna.
  • In analytics, focus on median and 95%, not average.
  • Set priority on assets. HTML/CSS are high priority. CSS blocks rendering for example. So are scripts, unless async / defer.
  • Split css according to breakpoint
  • Script found after image tags are given medium priority by Chrome
  • Canary dev tools - in settings hit SHIFT 6 times.
  • Network search. Hit cmd+f to search in files.
  • Devtools: cmd+shift+p to quickly jump to different views
  • In devtools you can expand the view to see more information about each resource to investigate issues
  • In devtools, Look at the time column. subtract the two times and see if it's worth making the file any smaller. It may not be, and instead focus on delivering it to the browser more quickly. Bottlenecks could be cause by bandwidth (file size) or latency.
  • event listener with array of fonts. when all have downloaded, apply 'fontsavailable' class, and this will repaint once for all three fonts.
  • Use local overrides in chrome to test changes. You can make changes and they'll persist locally. This allows you to run tests locally and possibly prove that your changes are beneficial.
  • You CAN have heavy pages which are fast.
  • Review order of head tags to optimize speed
  • CSS blocks JS execution. JS will not run until all CSS is downloaded.
  • Insert this into the DOM, so they measure from the rendered page. Before and after each head tag for example.
<script>
	performance.mark('startCSSFile');
	console.timeStamp('startCSSFile);
</script>
// some header tag
<script>
	performance.mark('DONE');
	console.timeStamp('DONE);
</script>
// then iterate over performance object and log each one to console.
  • Don't use @import in CSS
  • REORDER HEAD TAGS!
  • Measure the results
  • Avoid synchrinously linking to third party assets like fonts. Always load them asynchrinously. In the case of fonts... just self-host them since they're a critical asset. Think about uptime status and SLA. Google Fonts is pretty stable, but what if it went offline? What about Typekit?
  • If you do self-host, get the master source and do your own subsetting and hinting. Font providers like Google do this for you, making fonts look great on different devices.
  • Define your own cache strategy for your fonts. They don't change very often. Google Fonts busts their cache every 10 minutes...
  • Preconnect to resources needed later - use resource hints and prefetch
  • Avoid cdn script tags above the title

Loading resources in the right order

Loading resources in the correct order is critical for building a fast website; so do we have any bottlenecks or innefficiencies?

The optimum <head> order -- provided there are no interdependencies -- goes like so:

  • <meta charset />
  • <meta name="viewport" />
  • <title>
  • <link rel="preload | preconnect | dns-prefetch | prefetch" />
  • <script> // Inline JS </script>
  • <link rel="stylesheet" />
  • <style> /* Inline CSS */ </style>
  • <script src=""></script>

Use DevTool's Sources panel to test locally and run speed tests for each change

Manage user expectations

  • Service worker that can detect slow network connections, or detect if offline
  • Show placeholders for loading content - spinners, loaders, messages etc.
  • App designers use intro screens to distract the user while the app starts on first load.
  • Skeleton UI
  • Spinners with timeouts. If something goes wrong, present a call to action.

Performance testing

synthetic

  • controlled environment
  • profilling our own controlled
  • emulated

rum (real user monitoring)

  • how fast is it really?
  • measuring on real devices
  • new relic, speedcurve
  • available in google analytics as a cheap solution

WebpageTest

  • Pitfalls - use the most complete URL you can, avoiding 301 redirects - https://www.games-workshop.com/en-GB/ , not https://www.games-workshop.com
  • Advanced settings: location: run the test from a reasonable location that makes sense for your users
  • connection: Native is prone to change. Choose one (like Cable) and stick with it.
  • device: want to test on devices? use Virginia as your location
  • run multiple tests
  • save response bodies to check i18n
  • set minimum test duration
  • WPT has an API, it is scriptable - There's a book called Using WebpageTest
  • Lighthouse
  • Auth? Create a burner account because login details are transmitted
  • Script - You can exlude third party content for example, or run DOM manipulation (select locale or accept cookies for example) Simulate failure of specified domains. This is done by re-routing all requests for the domains to blackhole.webpagetest.org which will silently drop all requests.

Visual completeness.

What does the user see as the UI loads? Does content jump around during load? Is it a good experience?

Performance testing

  • Create a hypothesis
  • Test it
  • Repeat
  • Server Timing API

CSS performance

https://csswizardry.com/2018/11/css-and-network-performance/

Resource Hints

  • Use some templating logic, because the stuff you want to prefetch will vary depending on what page you're on.
  • Best implemented as HTTP headers to reduce manual maintenence overhead.

DNS prefetch:

  • Allow the browser to start warming up DNS connections before they're needed. If the domain is important and we know we're going to use it later. Third-party domain, CDNs etc. Only ever use for third party domains, not third or fourth etc.
  • Good if you know the domain, but not necessarily the files
<link rel="dns-prefetch" href="embed.youtube.com" />

Preconnect

  • Same use case as DNS prefetch
  • Doesn't work in older browsers, so use DNS prefetch as fallback.
<link rel="preconnect" href="https://fonts.google.com" />

Prefetch

  • Assets used in subsequent navigation / route / view
  • Eg. prefetch productImageCarousel.js while on landing page, or myAccount.js from login page. Let the application load the next resources while the user does something like fill in a form.

Example of prefetch/connect

<link rel="preconnect  dns-prefetch" href="https://cdn.carbonads.com">
<link rel="preconnect  dns-prefetch" href="https://srv.carbonads.net">
<link rel="preconnect  dns-prefetch" href="https://cdn.syndication.twimg.com">
<link rel="preconnect  dns-prefetch" href="https://platform.twitter.com">
<link rel="preconnect  dns-prefetch" href="https://syndication.twitter.com">
<link rel="preconnect  dns-prefetch" href="https://www.googletagmanager.com">
<link rel="preconnect  dns-prefetch" href="https://cdn.speedcurve.com">
<link rel="preconnect  dns-prefetch" href="https://www.google-analytics.com">
<link rel="preconnect  dns-prefetch" href="https://spdcrv.global.ssl.fastly.net">

Subresource

<link rel="subresource" href="/images/someBackgroundImage.jpg" />
  • A way to surface late discovered resources, like fonts or images loaded by css files.
  • BUT DON'T USE IT! It was rushed and it's insecure.
  • Use preloading instead.

Preloading

<link rel="preload" href="/images/someBackgroundImage.jpg" as="image" media="(min-width: 64em)" />

<link rel="preload" href="/fonts/someFont.woff2" as="font" type="font/woff2" crossorigin />
  • Like subresource but better
  • Keep an eye on chrome console / network panel for helpful warnings when you're implementing this.
  • Use the type attr for something like webP, where the browser may not understand the type. It won't preload it.
  • A bug in the spec. You always need to provide crossorigin attribute, even when same domain. Otherwise you'll get a double download.
  • Above the fold content, but whose natural download point would be quite late maybe buried in CSS. Fonts. Backgrounds.
  • Webpack can build these preloads for you.

Prerendering

  • For example, when user hovers over a thumbnail for a video, you could prerender the target of that thumbnail link and prerender the page.
  • Except no, you can't use this because it was poorly implemented, insecure, and people abused it.
<link rel="prerender" href="/shop" />
  • The browser would actually render that target

New better (aka no-state prefetch)

  • Now in Chrome it just sends the lookahead parser to scan over the target page. Still an improvement though.

Async / Defer

  • Javascript used to block parsing and execution.
  • It blocks downloads so other scripts arrive in the right order, to avoid race conditions.
  • Blocks DOM construction in case JS causes layout recalculation.
  • It's a good idea in the case of layout polyfill, Modernizr, client-side A/B tests, where applying classes would cause a lot of browser repaint.

Async

  • <script async>
  • No blocked downloads.
  • DOM construction not blocked.
  • Executes a script as soon as it arrives though, so not suitable for scripts which reply on any other files. Scripts may fire too early, like trying to find a DOM node which doesn't exist yet.
  • Scripts can arrive in any order
  • Good for important scripts with no dependencies, eg. responsive nav, carousel

Defer

  • <script defer>
  • Download asynchronously
  • DOM construction not blocked.
  • Executes scripts after everything else is done
  • Respects download order
  • They download in a random order, but they're queued so they run the correct order. DOMContentLoad is stalled until deferred scripts are ready and executed.
  • This will delay any other scripts which are waiting for DOMContentLoad
  • Good for anything not critical to user experience. Ads, user widgets, analytics, tracking codes etc. Anything not needed to build the page.

Anti-patterns

Base64 encoding images in CSS.

  • Moving non-critical assets onto your critical path.
  • Still downloaded as CSS payload even when image isn't used.
  • Images don't block rendering, but CSS can.
  • Doesn't Gzip very well.
  • SVG XML in HTML is ok though.

Asset domains for CSS

"Make CSS small, minify, compress,
load from the same hostname even (no DNS)
and inline, if small enough.”
— Stoyan Stefanov, csswz.it/2fYM2ei
  • Avoid trying to implement CDN style domains for CSS
  • Domain sharing CSS is an anti-pattern
  • Lengthens the critical path, increases network overhead
  • Keep critical assets on your main domain.

Scripts at the bottom of the page

  • Now considered an anti pattern
  • Delays loading JS far too late
  • No need since defer

Protocol-relative urls

  • <script src="//platform.twitter.com/widgets.js"></script>
  • Seems like a good idea if you're trying to run multiple microservices
  • Latency
  • No access to H/2

Async loading snippets

  • Hide assets from preload scanner
  • Async is available almost everywhere anyway

Debugging problematic CSS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment