Everything you need to know about Web Performance (in 5 Minutes)
Tags: webdev, performance, javascript, react
Published: 2022-06-23 15:00:53

**I hear a lot of people saying that web performance is hard. Honestly, I don't think that's true. It could feel complex and intimidating at first glance because there is a lot of domain-specific naming, metrics, etc but to build a fast website you don't need to know them. You only need a basic understanding of what influences the speed of your website the most and make sure you have it under control. Believe me or not, you can learn this in about 5 minutes. Let's see if I'm right!**

## What influences your app performance?

Let's start with identifying all the aspects that influence your app performance. I find this mental model most useful when thinking about web performance:

There are essentially three "steps" that sum up the overall loading performance of your app

1. **Server-side execution** - First the HTML document has to be generated on the server. In some cases, this step costs us nothing because it's already generated (static sites).
2. **Network** - The generated HTML document has to travel through wires and routers to arrive in the user's browser.
3. **Client-side execution** - The document needs to be parsed, and dependencies (CSS, JavaScript) have to be downloaded and executed. Once it's all done our page is fully loaded.

![Response Journey](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zejj3z1nnu6rrxwg9i7y.png)
 
## Optimizing server-side execution

If you're building a SPA (__Single Page Application__) there is a high chance you're also adopting SSR (__Server-Side Rendering__). In that case, the same code will run both on the server and the client sides.

The best code is the one that never has to run so you should first consider SSG (Static Site Generation). If it's not an option and you're sticking to SSR, make heavy use of full-page caching and distribute cached content through CDN.

![The fastest code is the one you don't need to run](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gk250d9agmxwpd6g6cbs.png)
 

Some pages will have to be generated on the server during runtime and just cannot be cached. Of those, make sure to fetch only fast, essential data on the server and make less important, and slower API calls on the client-side. This way you will significantly improve your Time to First Byte.

## Optimizing Network

Optimizing the networking part boils down to 4 main rules:

1. **Ship the smallest possible assets.** The bigger they are, the longer it takes to download them.
2. **Avoid chaining network requests** (making one request depending on another) and try to download them in parallel.Avoid using multiple external domains in the critical path. Establishing a connection with all of them will take more time than downloading everything from one source.
3. **Cache static assets** (HTML, CSS JS) through a Service Worker.

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9va5rci6lghh7iy2hlzd.png">
  <figcaption>Source: https://developer.chrome.com/blog/app-shell/</figcaption>
</figure> 

If you take care of that there is a much smaller chance you will run into performance bottlenecks on the network part.

## Optimizing client execution

This is where we, frontend developers, have the most power and where we also make a lot of mistakes! From my experience, 90% of frontend performance bottlenecks are around **rendering time** (that one can be easily solved with cached SSR and SSG output) and **interactivity** (that one can be solved by reducing amount of JavaScript in so-called critical rendering path through code splitting, lazy loading and being cautious with adding new libs to the clients).

The thing that usually leads to the biggest number of performance bottlenecks is JavaScript. In SPAs it's very easy to lose control over your JS bundle size. Here's what you can do to prevent it from growing into a Brontosaurus:

1. If you're using SSR/SSG it means that many of your components are already rendered on the server and they don't need interactivity on the frontend. You can drastically increase the speed of your hydration by hydrating only the components that need to be interactive and only when they need to become ones. You can use Astro.build or vue-lazy-hydration plugin if you're using Nuxt to control the hydration process and exclude the components that don't need it.
![Hydrate on Scroll](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/w1c8yucbd4mdr8dgjlgx.png)
2. Split your app into multiple lazy-loaded chunks (start with routes!). Every sidebar, modal or expensive widget can be loaded lazily on interaction.
![Code Split](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7yim098yr3gxy8npaa1p.png)
3. Your website could seem fast when you're building it but once the marketing team puts all the analytics there I guarantee it will slow down. You can use web workers to run the non-critical code asynchronously. I strongly recommend [Partytown](https://github.com/nuxt-community/partytown-module) - it's integrated with all major frameworks from the Vue ecosystem.
<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vz29r5xd99k9sqdyub00.png">
  <figcaption>Source: https://partytown.builder.io/</figcaption>
</figure>

## Optimizing images

Surprising amount of developers does a rookie mistake of not optimizing their images. To make sure images aren't the bottleneck simply adjust their size to the screen and use next-gen formats like webp. You can automatically resize and optimize your images using [<nuxt-img>](https://image.nuxtjs.org/) and/or [Cloudinary](https://cloudinary.com/). Also, load your below-the-fold images last. You can use native `<img loading="lazy" />` property for that.



## Measuring performance

If you can't measure – you can't say if there was any improvement. Measuring your performance constantly is as important as optimizing it regularly.

The performance metrics that have the biggest impact on user experience are called **Core Web Vitals (CVV)**:

- **Largest Contentful Paint (LCP)**: measures loading performance. 
- **First Input Delay (FID)**: measures interactivity.
- **Cumulative Layout Shift (CLS)**: measures visual stability. 

<figure>
  <img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/s74t6f06szzlr2qcncgw.png">
  <figcaption>Source: https://web.dev/vitals/?gclid=Cj0KCQjw2MWVBhCQARIsAIjbwoN567MYvlge9gXipQmZGvQG-9WZddKuQXRto_NiuIaHaTXStrjNFx0aApY9EALw_wcB</figcaption>
</figure> 

If you want to quickly check how your website is performing, try [Page Speed Insights](https://pagespeed.web.dev/). It will run a Lighthouse audit on your website using the closest Google Data Center.

You should also incorporate performance checks into your CI/CD pipeline. Use [Lighthouse CI](https://github.com/GoogleChrome/lighthouse-ci) to run a synthetic Lighthouse test on each PR (PS: [Learn why](https://dev.to/vue-storefront/youre-probably-using-lighthouse-wrong-how-we-got-tricked-by-a-single-magic-number-1laj) you shouldn't believe the Lighthouse score alone) and [bundlesize](https://www.npmjs.com/package/bundlesize) package to raise alerts if your bundle size exceeds a certain threshold. For more nuanced data you should use [WebPageTest](https://www.webpagetest.org/).

![Bundle Analysis](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7x1ss0t9uynul0gr7f9a.png)
 

Believe me or not but that's all you need to know to have your performance under control!


---
If you liked the article and want to learn more about web performance through articles and tips you can follow Vue Storefront profile here or [follow me on Twitter](https://twitter.com/filrakowski)