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
- 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).
- Network - The generated HTML document has to travel through wires and routers to arrive in the user's browser.
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.
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 the networking part boils down to 4 main rules:
- Ship the smallest possible assets. The bigger they are, the longer it takes to download them.
- 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.
- Cache static assets (HTML, CSS JS) through a Service Worker.
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 caused by two factors:
1. Unoptimized 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> and/or Cloudinary. Also, load your below-the-fold images last. You can use native <img loading=”lazy” /> for that.
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.
2. Split your app into multiple lazy-loaded chunks (start with routes!). Every sidebar, modal or expensive widget can be loaded lazily on interaction.
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 - it’s integrated with all major frameworks from the Vue ecosystem.
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.
If you want to quickly check how your website is performing, try Page Speed Insights. 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 to run a synthetic Lighthouse test on each PR (PS: Learn why you shouldn’t believe the Lighthouse score alone) and bundlesize package to raise alerts if your bundle size exceeds a certain threshold. For more nuanced data you should use WebPageTest.
Believe me or not but that’s all you need to know to have your performance under control!