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.
- 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.
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 Network
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 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:
- 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.
- Split your app into multiple lazy-loaded chunks (start with routes!). Every sidebar, modal or expensive widget can be loaded lazily on interaction.
- 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.
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 and/or Cloudinary. 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.
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!
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
Top comments (11)
The best way to sum performance up is:
Don't confuse performance optimization (ie, your code in regards to CPU cycles/memory) with caching at any level; one should always come before the other.
If your starting optimizations & are fullstack, Start at system OS calls levels in most cases on typical *nix OS: systrace + ps/htop/sysdig/newrelic/etc. Even before the days of "serverless" paying attention in particularly to any and all forms of I/O!
Disk/Network/System configs/etc. should always be a starting point if full stack. After then proceed to services like a web server, DB, etc. & Make frontend a half way point. Your
frontend code & clients will thank you. If not a full stack developer, kindly ask some metrics and questions to your DevOps team.
Just some notes from an old sr greybeard 🧙🏻♂️ optimizing performance on monolithic type open source code (Stares at Magento & PHP intensely.😵💫) Reference: an old stack answer of mine: magento.stackexchange.com/a/13992/69
I fully agree. It all starts with the infrastructure. This article is more targeted towards frontend developers, because this part is recently becoming main bottleneck of most applications, even tho it's not THAT hard to make it right :)
That was a great reading thanks for writing such a valuable article.
Great! Sometimes, it's easy to forget about performance while I'm working like in admin pages. I think it's good to being always aware of that.
Nice write up! Thanks for sharing.
By the way, if anyone is interested in going deep into web performance, I highly recommend the Web Performance Research repo.
Thanks! This repository is a true gem! Thanks for sharing it!
Came here after dev.js summit presentation. Great work! Thank you for sharing!
In Optimizing Network section you wrote "Optimizing the networking part boils down to 4 main rules". I understand you deliberately left 4th rule to be forever a mystery ;)
Great article and summary Filip, thank you. Just a small comment: you mention there's 4 points on Optimizing the Network but you only mention 3 😬
Very cool summary of the most important information on performance optimization 👍💪
Ordered list in part 2 is a bit broken 🤫
Thank you, fixed!
I noticed an typo!
Only 3 were listed! :-)