Optimizing interactivity of product details pages for a 90% reduction in Max Potential FID in Lighthouse and a 9% improvement in FID in Chrome User Experience Report.
Mercado Libre is the largest e-commerce and payments ecosystem in Latin America. It is present in 18 countries and is a market leader in Brazil, Mexico, and Argentina (based on unique visitors and pageviews).
Web performance has been a focus for the company for a long time, but they recently formed a team to monitor performance and apply optimizations across different parts of the site.
This article summarizes the work done by Guille Paz, Pablo Carminatti, and Oleh Burkhay from Mercado Libre's frontend architecture team to optimize one of the Core Web Vitals: First Input Delay (FID) and its lab proxy, Total Blocking Time (TBT).
90%
Reduction in Max Potential FID in Lighthouse
9%
More users perceiving FID as "Fast" in CrUX
Long tasks, First Input Delay, and Total Blocking Time
Running expensive JavaScript code can lead to long tasks, which are those that run for more than 50ms in the browser's main thread.
FID (First Input Delay) measures the time from when a user first interacts with a page (e.g. when they click on a link) to the time when the browser is actually able to begin processing event handlers in response to that interaction. A site that executes expensive JavaScript code will likely have several long tasks, which will end up negatively impacting FID.
To provide a good user experience, sites should strive to have a First Input Delay of less than 100 milliseconds:
While Mercado Libre's site was performing well in most sections, they found in the Chrome User Experience Report that product detail pages had a poor FID. Based on that information, they decided to focus their efforts on improving the interactivity for product pages in the site.
These pages allow the user to perform complex interactions, so the goal was interactivity optimization, without interfering with valuable functionality.
Measure interactivity of product detail pages
FID requires a real user and thus cannot be measured in the lab. However, the Total Blocking Time (TBT) metric is lab-measurable, correlates well with FID in the field, and also captures issues that affect interactivity.
In the following trace, for example, while the total time spent running tasks on the main thread is 560 ms, only 345 ms of that time is considered total blocking time (the sum of the portions of each task that exceeds 50ms):
Mercado Libre took TBT as a proxy metric in the lab, in order to measure and improve the interactivity of product detail pages in the real world.
Here's the general approach they took:
- Use WebPageTest to determine exactly which scripts were keeping the main thread busy on a real device.
- Use Lighthouse to determine the impact of the changes in Max Potential First Input Delay (Max Potential FID).
Use WebPageTest to visualize long tasks
WebPageTest (WPT) is a web performance tool that allows you to run tests on real devices in different locations around the world.
Mercado Libre used WPT to reproduce the experience of their users by choosing a device type and location similar to real users. Specifically, they chose a Moto 4G device and Dulles, Virginia, because they wanted to approximate the experience of Mercado Libre users in Mexico. By observing the main thread view of WPT, Mercado Libre found that there were several consecutive long tasks blocking the main thread for 2 seconds:
Analyzing the corresponding waterfall they found that a considerable part of those two seconds came from their analytics module. The main bundle size of the application was large (950KB) and took a long time to parse, compile, and execute.
Use Lighthouse to determine Max Potential FID
Lighthouse doesn't allow you to choose between different devices and locations, but it's a very useful tool for diagnosing sites and obtaining performance recommendations.
When running Lighthouse on product detail pages, Mercado Libre found that the Max Potential FID was the only metric marked in red, with a value of 1710ms.
Based on this, Mercado Libre set a goal to improve their Max Potential FID score in a laboratory tool like Lighthouse and WebPageTest, under the assumption that these improvements would affect their real users, and therefore, show up in real user monitoring tools like the Chrome User Experience Report.
Optimize long tasks
First iteration
Based on the main thread trace, Mercado Libre set the goal of optimizing the two modules that were running expensive code.
They started optimizing the performance of the internal tracking module. This module contained a CPU-heavy task that wasn't critical for the module to work, and therefore could be safely removed. This led to a 2% reduction in JavaScript for the whole site.
After that they started to work on improving the general bundle size:
Mercado Libre used webpack-bundle-analyzer to detect opportunities for optimization:
- Initially they were requiring the full Lodash module. This was replaced with a per-method require to load only a subset of Lodash instead of the whole library, and used in conjunction with lodash-webpack-plugin to shrink Lodash even further.
They also applied the following Babel optimizations:
- Using @babel/plugin-transform-runtime to reuse Babel's helpers throughout the code, and reduce the size of the bundle considerably.
- Using babel-plugin-search-and-replace to replace tokens at build time, in order to remove a large configuration file inside the main bundle.
- Adding babel-plugin-transform-react-remove-prop-types to save some extra bytes by removing the prop types.
As a result of these optimizations, the bundle size was reduced by approximately 16%.
Measure impact
The changes lowered Mercado Libre's consecutive long tasks from two seconds to one second:
Lighthouse showed a 57% reduction in Max Potential First Input Delay:
Second iteration
The team continued digging into long tasks in order to find subsequent improvements.
Based on that information they decided to implement the following changes:
- Continue reducing the main bundle size to optimize compile and parse time (e.g. by removing duplicate dependencies throughout the different modules).
- Apply code splitting at component level, to divide JavaScript in smaller chunks and allow for smarter loading of the different components.
- Defer component hydration to allow for a smarter use of the main thread. This technique is commonly referred to as partial hydration.
Measure impact
The resulting WebPageTest trace showed even smaller chunks of JS execution:
And their Max Potential FID time in Lighthouse was reduced by an additional 60%:
Visualize progress for real users
While laboratory testing tools like WebPageTest and Lighthouse are great for iterating on solutions during development, the true goal is to improve the experience for real users.
The Chrome User Experience Report provides user experience metrics for how real-world Chrome users experience popular destinations on the web. The data from the report can be obtained by running queries in BigQuery, PageSpeedInsights, or the CrUX API.
The CrUX dashboard is an easy way to visualize the progress of core metrics:
Next steps
Web performance is never a finished task, and Mercado Libre understands the value these optimizations bring to their users. While they continue applying several optimizations across the site, including prefetching in product listing pages, image optimizations, and others, they continue adding improvements to product listing pages to reduce Total Blocking Time (TBT), and by proxy FID, even more. These optimizations include:
- Iterating on the code splitting solution.
- Improving the execution of third-party scripts.
- Continuing improvements in asset bundling at the bundler level (webpack).
Mercado Libre has a holistic view of performance, so while they continue optimizing interactivity in the site, they have also started assessing opportunities for improvement on the other two current Core Web Vitals: LCP (Largest Contentful Paint) and CLS (Cumulative Layout Shift) even more.