Fast from the Start

The cost of JavaScript, my top tips for measuring and optimizing performance, and how wasps can help us ship faster websites.

Issue 5 /

Hey there,

If you ever worked with me you know how much I love talking about web performance. I usually share a few performance resources here in the newsletter, but in general, I try to keep it light and diversify the content a little bit.

Well, not today! This week's issue of Frontend at Scale is (mostly) all about web performance; we'll talk about the cost of JavaScript, my top tips for measuring and optimizing performance, and we'll even see about how wasps can help us ship faster websites. Let's dive in!


Fast from the Start

Photo by Steven Lelham on Unsplash

Learning about web performance can sometimes feel like reading a business book; it's all fun and games until the acronyms show up.

Okay, business books aren't fun and games at all, but my point still stands. Open any web performance report, and you'll find yourself facing a wealth of different metrics, usually in the form of a three-letter acronym such as FCP, LCP, FID, CLS, TBT, INP, TTI, and the like.

If you're a performance expert, these reports are like music to your ears. But if you're just getting started, they can feel like a lot.

So today I want to share my top tips for anyone taking their first steps in the fascinating but confusing world of web performance. If you're looking to make your websites faster but are unsure where to start, my advice is simple: ship less JavaScript, take meaningful metrics, and remember to measure runtime performance as well.

Ship Less JavaScript

You'll notice this is a theme throughout today's newsletter, and there's a good reason for it. JavaScript is the most expensive type of resource you can deliver to user's devices, and lots of modern websites today ship way too much of it.

Some people will use this fact to argue for or against a specific JavaScript framework. While it's true that your choice of framework impacts how much JavaScript your website ships by default, the reality is that you can achieve great performance with just about any of them.

The challenge is not so much creating a fast website, but maintaining good performance over time and keeping bundle sizes in check as your website grows in complexity.

My favorite strategies for shipping less JavaScript are code-splitting (which can be done at a route or component level), replacing or eliminating third-party dependencies, and keeping unused code to a minimum.

Easier said than done, I know, but there are a lot of great tools that can help us with it. Some of my most frequently used are:

  • Webpack Bundle Analyzer, or a similar package for non-Webpack bundles, such as vite-bundle-visualizer or Lighthouse Treemap. These tools let you see the composition of your bundles via a treemap visualization, which makes it easy to identify heavy modules and third-party dependencies.
  • Chrome DevTools Coverage Report: a simple-to-use dev tool in Chrome that tells you how much of your shipped JavaScript and CSS code is not being executed. Coverage reports are great for finding opportunities for code-splitting dead code elimination.
  • bundlesize: a small and easy-to-use tool that checks your bundle size after every build as part of your CI pipeline. You can set limits for how much you're willing to let your bundles grow, and bundlesize will break your build if you go over them.
A build failure caused by bundlesize

Take Meaningful Metrics

Before we can talk about specific performance metrics, it's important to define the two different types of metrics that we can measure: lab metrics and field metrics.

Lab metrics are gathered via synthetic testing tools like Google Lighthouse or WebPageTest, and they measure your website's performance at a particular moment in time and on specific device and network conditions. Lab metrics might not represent your typical customer experience, but they're useful as a baseline for measuring your progress during development.

Field metrics, on the other hand, are gathered by browser APIs and Real User Monitoring (RUM) tools from your real visitors. These metrics are a more accurate representation of how your users experience your website, but they take longer to collect and can be quite expensive depending on how popular your site is.

The next thing to figure out is which metrics are worth tracking. There are tons of different ones, and trying to measure each one of them can be a daunting task, even for the most performance-focused organizations.

A good place to start is by measuring Core Web Vitals. This is a set of user-centric metrics with the goal of measuring loading performance, interactivity, and visual stability. The current set of Core Web Vitals as I'm writing this are:

  • Largest Contentful Paint (LCP): measures loading performance by reporting the render time of the largest image or text block on the page.
  • First Input Delay (FID): measures interactivity by reporting the time it takes to respond to the first user interaction.
  • Cumulative Layout Shift (CLS): measures visual stability by tracking how much your page's content unexpectedly shifts around.
The current set of Core Web Vitals

A new metric called Interaction to Next Paint (INP) will soon replace FID to become a new stable Core Web Vital. INP is measured over the course of a user's visit rather than just the first interaction, and it's been proven to be a more accurate measurement of your website's responsiveness.

The up-and-coming INP metric, which will become a Core Web Vital in March of next year

Measure Runtime Performance

Users will interact with your website beyond the initial page load, so ensuring a fast and responsive runtime experience is also very important—particularly for single-page applications where most user interactions do not cause a full-page refresh.

My favorite way of measuring runtime performance is using the Chrome DevTools Performance panel. You can start a performance recording at any time, perform any number of interactions, and then stop the recording to see the result.

A performance recording produces a comprehensive but quite intimidating report. Will it feel overwhelming the first time you look at it? Yes. But will it still feel overwhelming after the 1,000th time? Also yes.

There's a new Performance Insights panel that gives you actionable tips for improving your site's performance via a much simpler report. I like this panel for measuring Web Vitals and page-load performance, but I find the traditional Performance panel more useful for runtime metrics.

In particular, I like to focus on these two areas:

  • The Main thread panel—look for long tasks, which are easily distinguishable by their striped red background. These are tasks (typically a JavaScript function call) that take more than 50ms to resolve. Since these tasks are running on the main thread, any user interaction during their execution will be unresponsive, causing sluggish experiences and frustrated users.
  • The Network panel—look for resources that take too long to download or request waterfalls that could be parallelized. Pay special attention to this tab when lazy-loading scripts or navigating between routes on a single-page application.
A typically intimidating performance report. Look for slow requests and waterfalls on the network panel (1) and long tasks on the Main thread panel (2)

Lastly, keep in mind that performance snapshots taken this way will give you lab data. Interactions might feel snappy on your device, but that doesn't necessarily mean it will feel the same for your users. It's generally a good idea to turn on throttling to simulate a 4x CPU slowdown to ensure users on lower-power devices also get a great experience.

We've only touched the surface of everything there's to know about web performance, but hopefully, this will give you a solid starting point.

If you're looking for more advanced web performance content, you're in luck! You'll find other great resources in today's newsletter.


The Cost Of JavaScript - 2023

We talked about the importance of shipping less JavaScript in today's essay, but if you're wondering why JavaScript is such an expensive resource, look no further than Addy Osmani's talk The Cost of JavaScript.

Addy talks about the two key problems with shipping too much JavaScript to client devices: download times are critical for slow networks, and JavaScript execution time is critical for devices with slow CPUs.

So it's important to optimize for both hardware and network. We can do this by (you guessed it) keeping our JavaScript bundle sizes to a minimum and using strategies such as pre-loading, prefetching, priority hints, code-splitting, and importing on visibility.

This talk is also my favorite way to keep up with modern and evolving rendering patterns. Server-side rendering, islands architecture, server components, and resumable hydration are all covered in great detail with clear examples and visualizations. And if you're looking for a deeper dive on this subject, Addy and Lydia Hallie wrote an excellent guide on their book

Bonus: Katie Hempenius gave a talk at last year called What’s new in performance? Perfect for keeping up with the latest tools and resources beyond JavaScript optimization.


Links Worth Checking Out

We've been talking about React Server Components for a while now, but the pattern can still lead to some confusion. Thankfully, Josh wrote a fantastic guide to help us make sense of them, which is also part of his upcoming and amazingly looking course The Joy of React.

Did you know you can define types for your CSS custom properties? @property lets you do exactly that, with types that are enforced both during development and in the browser.

The Shopify team wrote a detailed case study on how they tackled three of their biggest performance challenges with layout position: lazy-loading images, loading asynchronous CSS, and prioritizing the LCP.

Understanding the distinction between owners and parents is essential for composing React components correctly. This visual guide, full of interactive examples, clearly explains the differences.

Astro 3.0 launched a couple of weeks ago, and one of the most exciting new features is its built-in support for the View Transitions API. I had the pleasure of contributing a small part to this article, so this one is a bit of a shameless plug 😊


Responsible JavaScript

Responsible JavaScript by Jeremy Wagner is my number one book recommendation for frontend developers who want to learn more about web performance. It's a short book (around 180 pages), it's fun, and it's packed with valuable tips for making your websites faster.

The book talks about the very important role of JavaScript in performance and how shipping too much of it can cause sluggish experiences and inaccessible content. It doesn't advocate for zero-JavaScript, but it does ask us to be more intentional about the code we ship to our user's devices.

In its seven chapters, you'll learn about:

  • Strategies for shipping less JavaScript: code splitting, caching, using platform APIs.
  • Measuring and assessing JavaScript performance: lab vs. field metrics, painting metrics, and measuring layout stability and main thread responsiveness.
  • Optimizing load-time and runtime performance: how the browser's main thread works and ways in which we can parallelize tasks.
  • Managing third-party scripts: self-hosting, pre-connecting, and lazy-loading.

Plus, you'll learn a number of interesting facts about different species of wasps. That's right, wasps. If you're wondering what this has to do with JavaScript performance, check out the book's website.

That’s all for today, friends! Thank you for making it all the way to the end. If you enjoyed the newsletter, it would mean the world to me if you’d share it with your friends and coworkers. (And if you didn't enjoy it, why not share it with an enemy?)

Did someone forward this to you? First of all, tell them how awesome they are, and then consider subscribing to the newsletter to get the next issue right in your inbox.

I read and reply to all of your comments. Feel free to reach out on Twitter or reply to this email directly with any feedback or questions.

Have a great week 👋

– Maxi

Is frontend architecture your cup of tea? 🍵

Level up your skills with Frontend at Scale—your friendly software design and architecture newsletter. Subscribe to get the next issue right in your inbox.

    “Maxi's newsletter is a treasure trove of wisdom for software engineers with a growth mindset. Packed with valuable insights on software design and curated resources that keep you at the forefront of the industry, it's simply a must-read. Elevate your game, one issue at a time.”

    Addy Osmani
    Addy Osmani
    Engineering Lead, Google Chrome