At a large retail company in BC, Canada, we were faced with a monolithic problem of an underperforming and over-bloated Storefront web app, built using React. Thus to address this growing concern over performance, scalability and security a team was built. Performance as a subject is an ocean, and to be tasked with solving for it is like searching for the needle in the ocean.
The first obvious place to look would be to look at some metrics. But what metrics should we be looking at? The key metrics we identified were LCP (Largest Contentful Paint), TTI (Time To Interactive) & CLS (Cumulative Layout Shift). Of course, these weren't the only metrics that we focused on, apart from the above we also kept an eye on our speed-index, bundle sizes, which were, like I mentioned earlier, extremely bloated.
Why these metrics?
Though many other metrics play into performance, these metrics address key components that are detrimental to performance.
LCP - Tracks how long it takes to load the largest content on the page. This is usually the "above the fold" content.
TTI - Tracks how long it takes before the page is interactable.
CLS - Tracks visual stability.
Also, note that these metrics are vital to obtaining a good Lighthouse score.read more.
How to track these metrics
We identified Lighthouse as the main tool to track the above metrics. Lighthouse is an open-source tool provided by Google.
This tool is available in 3 different forms -
- It is available in the Chrome browser under the dev-tools.
- It is available as an npm package that can be run on the CLI.
- It is available on the web.
Google also provides a web-vitals library that enables you to use in your React-App to collect the above metrics as Real User Metrics (RUM).
We observed that each of these tools gave different metric results for a given page. So it'll be a good idea to decide early on which tool works best for you.
At the time of writing this article, we decided to use the Chrome dev-tool version of Lighthouse in the interest of time, with plans for an automated/triggered pipeline for Lighthouse tests.
We also monitored our results on WebPageTest.org to track other vital metrics, like file size, Time To First, performance on subsequent requests, etc.
How to improve performance?
While the metrics discussed above give some insight into areas that need improvement, to identify possible opportunities within a React App, Webpack Bundle Analyzer is just the tool for the task.
As you can see our internal library (bbyca) was duplicated multiple times.
There were two reasons for this behaviour -
- For one we started using strict versions (not following semantic versioning standards), i.e instead of using
<package-name>: "^x.x.x"we started removing the "^" from a maintainability standpoint. (not that I particularly agree with the idea, but that's a discussion for another time).
- And to make matters worse each internal package used a different version of bbyca.
These two points together made it impossible for npm and/or Webpack to deduplicate these internal packages. Thus bloating our vendor file(s).
Now there are multiple ways to solve this. In most cases avoiding the above mentioned bad practices would usually steer you clear of these issues. What we chose to do was to slowly move our internal packages into a mono-repo to enable package version synchronization across our internal packages (and apps in the future).
This greatly reduced our vendor file size (by about 50%). And of course, that intern did yield some performance gains.
metricsbeforeAfterLighthouse performance3249First Contentful Paint0.9s0.8sTime to Interactive5.0s4.3sSpeed Index2.9s2.7sLargest Contentful Paint3.5s1.5s Stay tuned for more on how to reduce the bundle size in part II (coming soon).
If you like what you have read so far please like, share & subscribe. If you have questions feel free to leave a comment and I'll try my best to respond at the earliest. ✌️