In Today’s Web industry, performance is more important than ever. During my last years of development, I had the opportunity to work with many codebase and gained vital experience related to SPA performance.
In today’s article, I am going to share some of this insight that may help you in speeding up your application, and improve your site speed and User Experience (UX).
Disclaimer: I know my website is very bad in performance. It is a wordpress site, and I have no time or will to improve it (spending time on it, won’t pay the bill.. 🙂 )
What is performance?
This is really a million dollar question… Every Web Application may define “performance” differently due to their client base and overall architecture of the app. In this article I am going to provide different examples that may be used to help a number of use cases.
There are a few different topics that will be covered in this article. We are going to talk about Bundle size, Network requests, Time to interactive and much more. Most of these are quite advanced topics, and good knowledge of web development is suggested.
How to test performance
Performance is a moving target as the industry changes so quickly, that is is very difficult to always be at the top of the game.
Luckily there are a couple of tools out there that can help us to keep up to date. One of the most known and simple to access is Lighthouse (https://developers.google.com/web/tools/lighthouse).
This is an Open source tool offered by Google that helps you to quickly analyse any website. The google website introduce this tool as:
Lighthouse is an open-source, automated tool for improving the quality of web pages. You can run it against any web page, public or requiring authentication. It has audits for performance, accessibility, progressive web apps, SEO and more.https://developers.google.com/web/tools/lighthouse
There are many tools out there, but the main reason why I always suggest lighthouse is because it always inline with what google expect, and it is always good to try and align with the biggest search engine online.
In this article we are not actually going to analyse the lighthouse report and or using it as a baseline, as much as I think it is a great tool that MUST be looked at during an application development, I also think that it is essential to learn how to “improve” performance during your day to day development.
How to test performance (while developing)
It is now time to start and analyse what are the best way to improve our application and really learn how to test and improve the performance of our app
1 – Bundle size
The first and foremost rule is “look” at your bundle size. In frontend development it is becoming extremely simple to load up NPM packages for very simple tasks without looking at the overall impact that they may have on the application.
To improve bundle size there are a couple of simple action that can be taken. The following are related to Webpack, but the equivalent can also be found for other tools.
- Tree Shaking: Elimination of “unused” code from the bundle
- Code splitting: Ability to split the code in various bundle (js file) that can be loaded if/when needed
- Webpack analyser: Visualizing tool for Webpack bundle
2 – Service worker and PWA
If you are researching about performance, you have surely stumbled upon the words “service worker” and “PWA”. When providing performance to your clients is essential, then the service worker is a must have.
In quick words, implementation of a Service worker, will provide you the ability to set up multiple strategies to handle your network request (and much more). The service worker can be seen a “middleman” between your site and the internet.
A well defined strategy will allow you to cache important file of your application, hydrating website with the latest api calls while new information are gathered, and setup “background sync” to make your site snappy.
Unfortunately, service worker are not very mature yet, and the documentation that can be found around is not the best, but frameworks are starting to catch up with simple to use plugins and useful documentation.
3 – Image Size
Every website currently live, will have some sort of images within it. Sometimes is just for the user profile picture, some other may be as blog post headers, or just to show-cast a restaurant with a massive banner.
Images even if very widely used, they are not usually optimized. Most images that are provided from designers and used within website, are coming directly from a design tool and are usually as big as they could be.
The first step I take when analysing a website or web app, is to check at the images. Image compression (and sometimes change of format) can provide up to 80% of savings without quality loss.. yes you have seen it right 80%.
Another very great cost saving, can be serving the correct images for the right device size. I first experience this while working on gatsby, as it provide a fantastic images API that really supported me in understanding how to use the
<img> element properly.
4 – Async / Await & Promises
I have left this for last, because it is the one that I want you to remember the most, due to its importance and ease of implementation.
The three points covered in my previous sections require individual development and or research, and as such are less luckily to be done and implemented in all projects (even if I think they should both be a must have for any project). In this section, we are going to cover a very simple and sometimes overlooked code implementation that can really support your app loading time.
Unfortunately, in many instanced, I have seen the code being miss-used, resulting in a slower application.
The best way to show where the issues may lie is by providing a simple example. Let’s assume that I am setting up my application and I am loading up all the required assets in its initialization method:
const style = await api.getCustomStyles();
const articles = await api.fetchLatestArticles();
const user = await api.getUser();
I have seen and developed implementation like the one showed above many times, and until I really looked at it in details I never saw anything wrong with it, as it really looked nice and clean. Our application does require this data, and we need to WAIT for it before we can load it all up..
The problem with the code above, is that it will produce an unwanted “stairs” effect (I named it this way, I am not sure if it actually has a name).
In fact each request is going to be triggered in sequence:
- We are going to call the api for the custom styles
- when it come back we are going to fetch the latest article
- Then finally we will get the user.
If we assume each of the request to take 200ms, we would take a full 600ms before the method is completed.
If there is no real need for the request to be sub sequential (it would just be necessary if you needed data from one to send to the next one), it is usually a good idea to use Promise.all. This method will trigger ALL the promises together, fulfilling the promise as soon as they are all done (or rejected):
const [style, articles, user] = await Promise.All([
Performance is not actually simple, and in many cases it is never budgeted and/or factored in the overall application development. Improving your day to da development by considering the above few tips and tricks can really make massive improvement in your application.
If you want to go any further I really suggest to start and analyse the lighthouse report and it provide your lots of useful information that can help you define what your really need to focus on.