I would like to begin by citing my mentors & teammates who helped me to understand the concepts & enhance my knowledge on performance improvements of the Website. It was a collaborative effort across teams from the planning stage till taking things to Production. The list of people whom I would want to thank is quite long but would want to cite a few notable people who had a larger influence in making this happen:
Hidayat Febiansya (https://www.linkedin.com/in/hidayat-febiansyah-9a3641140/ ,working at Blibli.com)
Friska Nataniel (https://www.linkedin.com/in/friskanataniel/, working at Blibli.com)
Anand Kumar Tiwari, (https://www.linkedin.com/in/anand-tiwari-30455b105/, working at Quinbay )
Here's the brief heads-up:
UI Rendering was slow on Search Listing pages in our site as we had multiple cross-cutting components being loaded during the rendering of the page. There were also these redundant & sub-optimal recursive implementations which eventually built up over a period of time.
The listing page though owned by one part of the team; had several modules that were managed by different teams.
The framework and the supporting tools we use are as below:
Javascript Framework : Vuejs 2.0
https://www.npmjs.com/package/intersection-observer-polyfill (used for lazy loading of components)
https://developers.google.com/web/tools/lighthouse (UI testing tool)
https://developers.google.com/web/tools/chrome-devtools/coverage (by this tool we can easily identify the unused CSS and javascript code on our page)
https://developers.google.com/web/tools/chrome-devtools/evaluate-performance/reference
Diving into the waters right away …. how we swam through
Some of the BIG things we identified to be addressed immediately were as below:
Changing Image format from JPEG to WEBP
Until recently we were using JPEG format while rendering images on site. JPEG is heavier and for some odd reason, we had been reliant on using jpg through WebP which is a far more improved version of image formatting techniques that supports both lossy & lossless compression was published 10 years ago.
WebP is an image formatting technique that uses both lossy and lossless compression. For more details, you can refer to: https://developers.google.com/speed/webp/faq
As of the day of this writing, neither Firefox nor Safari had native support for WebP. This wasn’t a big deal for us to handle, because in Safari and Firefox users will still be rendered with JPEG version of the images. But the major chunk of users we have is luckily on Chrome or Edge. So, we had the support of Users intuitively.
Create Webpack chunk names
Webpack as the name suggests bundles modules of the project by building a dependency graph. This allows you to split your code into various bundles which can then be loaded on-demand or in parallel. It can be used to achieve smaller bundles and control resource load prioritization which, if used correctly, can have a major impact on load time.
But for these bundles, we give names to identify which bundle comprises which components and node modules. So, by this, we can identify the unnecessary modules loaded in that bundle and remove that.
Single page application constraints:
If your web application comprises multiple modules handled across multiple teams and each renders part of the single page application, it, therefore, requires Code review from time to time across teams to avoid any Internal URL redirections, etc, that would break the principle functioning of SPA.
We had a scenario where the Search pages of our E-Commerce site (blibli.com) was redirected to different URL paths based on different types of requirement like SEO, brand or merchant pages.
As search pages are rendered along with other components that are not purely under the purview of Search, the URL redirections caused us to re-load the page instead of just refreshing the result portion of the page. We identified these simple concerns in the tech-debt part of a sprint to improve the performance of the site and fixed the point of concerns.
Lazy loading of components & Images
One needs to identify the parts of the site/app that can be loaded lazily. Meaning request the resource only when the user demands to view those sections explicitly and not to load the entire page on the first interaction.
This way we can reduce the network bandwidth used, the number of resources loaded in the site, the number of calls to the site, or static resources. All in all, you can find a lot of benefits from this behavioral change of site. One can find enough tech articles describing the implementation of such a pattern.
Code Refactoring
Let’s take an example of a tree-structure component of an E-Commerce site as shown below:
As and when the user chooses an option an API call is made to reflect the changes caused by this user action. In an API call if it is not fast enough the end-users would see the screen frozen for a moment before reflecting the changes (even the selection status of the option).
The solution we identified was as below:
Not to manipulate the DOM
Show the tick mark when the user clicks on the check box.
Reduce recursions in tree-view components that are unnecessary usage of computed properties.
Call trackers only after successful execution of the call.
Have loaders if the API calls take a longer time.
We observed the change in experience for users and thus engagement on these tree-structured UI interactions too improved. What we finally saw …
Our overall website performance improved and thus User engagement increased. As per the lighthouse reports, we could see that improvements were justified and measurable through these actions.
Our site performance before the above upgrades:
And improved to this after the changes:
This is not to say that we are done with the performance improvements and we are at the pinnacle of it. Rather this is just a start and there are still major upgrades happening on the performance as I write this article. I will share once we see its light. Till then…Adios 👍
Also read our another blog on Discovering the ‘Science’ in Data Science – Part 2
Comments