Techniques for Improving Your Front-end App’s Performance
A journey of triaging page load issues and identifying tangible steps to resolve them
These days, people simply do not have patience for slow websites — the BBC found that it lost an additional 10% of users for every second its site took to load. And as we know, unhappy users equals lost revenue and diminished brand reputation. Also, today about half of web traffic worldwide comes from mobile devices, where pages inherently load slower. Luckily, there are many strategies to diagnose and resolve performance issues. On a recent internal project with Slalom Build, we made use of some handy tools to remove unused JavaScript and compress images, which significantly sped up our page loads.
Using Lighthouse to Identify Performance Issues
In order to understand the drivers of performance issues on our project, we used the Google Lighthouse performance scoring tool. When we ran the report, this was the initial result:
We can see that the Largest Contentful Paint score was a top driver of subpar performance. To improve the page load speed, Lighthouse recommended that we remove unused JavaScript, which could save 3.63 seconds from the page load.
Using Webpack Bundle Analyzer to Visualize Packages
Our project was a single-page application bundled with Webpack, which meant that we could use Webpack Bundle Analyzer to examine our project. This tool creates an interactive tree graph of the contents of all of your bundles, allowing you to visualize the relative size of all the modules in your project. Check out this blog post for more details on how to configure and use the Webpack Bundle Analyzer.
When we installed the bundle analyzer, we got this graph:
You can see that we have two big tan and blue outer boxes, which represent the two JavaScript files that are generated by the build (chunk-vendors.js
and app.js
, respectively). The size of the boxes represents the size of the JavaScript files, so it is clear that our dependencies (chunk-vendors.js
) are much larger than the code we wrote (app.js
). Within the big boxes, there are smaller boxes that represent individual modules, and there are files within those modules. If you hover over one of those modules, you will see a dialog with its size:
The components in the MyOpportunities directory made up 19.2% of our app.js
bundle’s size. The “My Opportunity” feature had been under development for many months under a feature flag, but it had recently been pushed back indefinitely due to the need for a redesign. As a result, it was taking up valuable real estate on our production package, as the bundle analyzer proved to us. We were able to safely extract all of the My Opportunity components from our project, making sure to add a Git tag with documentation for how to recover the files if and when the feature was resumed down the road.
In addition to the My Opportunity components, a few npm packages were taking up significant space in our bundle, specifically vvo/tzdb
(199.9 KB) and date-fns
(145.6 KB). Since both of these libraries were used primarily by the My Opportunities features, we were able to remove them with minimal effort once we deleted the My Opportunity components.
After removing the My Opportunity components, vvo/tzdb
, and date-fns
, this was the new graph that we got from the bundle analyzer:
Our overall JavaScript bundle size went down from 1.01 MB to 765.9 KB, a 24% decrease!
Before:
After:
Compressing Images
After our effort to reduce unused JavaScript, we began a very different exercise — compressing images. In our Lighthouse performance scan, one of the top opportunities was “Serve images in next-gen formats.”
Our home page had many images, but they were all saved as uncompressed PNG or JPEG formats. As a result, the files were quite large and slowed down the page load. Google recommends image formats like WebP and AVIF, which have better compression then the older formats like PNG or JPEG. While we could have converted our images to those formats, neither of them offered full browser compatibility, which was a requirement for our project. As a result, we opted to use compressor.io to compress all of our images, while maintaining the original formats and sizes. We compressed our images down from 10.2 MB to 3.3 MB (68%) without any noticeable difference in quality!
Conclusion
To recap — we were able to optimize our bundled JavaScript by gathering performance data using Lighthouse Performance reports, visualizing our modules through the Webpack Bundle Analyzer, and finally removing large dependencies that were no longer needed. We also compressed our images to improve their download speeds. All of these efforts had a significant impact on our Lighthouse performance scores.
Before:
After:
Although there are many other important methods of boosting front-end performance such as caching, g-zipping, prefetching, and using CDNs, I’ve found that compressing images and eliminating unneeded JavaScript can offer some low-hanging fruit and has the added benefit of cleaning up a project’s repositories while delivering only what is truly needed to the end user.
Further Reading: