How we reduced our website build time by 59%

My name is Aikansh, and I am an intern with the Ops Engineering team at Fyle. During my tenure here, I've absolutely loved working with such talented people over the 6+ months I've spent here. I've learned more about Expense Management than I ever thought I would, and I'm grateful for all the knowledge, support, and guidance the team has provided me. :)

What do I do at Fyle? 

During my internship, I've loved working on the usability issues module, which gave me exposure to varied microservices and how they work in sync. 

Our web strategists, content specialists, and web designers help create the desired results together. However, as developers, we need to tie all the pieces together with the right code for the website. We also run multiple tests to ensure that the site is bug-free and stay alert to be the troubleshooters when necessary.

This internship has helped me hone my skills in front end technologies, workflow in a start-up, management among teams, the importance of design docs, and understanding products we build from the users' perspective. Here’s my experience in reducing our website build time by 59%.

Context to the situation 

For our website, we use the versatile webpack as our module bundler and the excellent jekyll as our site generator. In summary, what we do is compile our ES6 code into an ES5 bundle and place it in Jekyll's main /assets directory. During development, we have Jekyll's server watch for changes and reload the page every time it detects a change in our JavaScript code.

The Problem

As is always the case given the speed of development, our web pages, components, and webpack config grew organically, and the speed of the pipeline was an after-thought. 

Often we had to wait 10 whole seconds for our build to apply simple changes like color:black; to color:blue; :/

But there came a tipping point. Eventually, we snapped and decided to get that build time way down.

tl;dr version

We reduced the build time by 59% with some minor tweaks. (As a bonus, my teammates also like me a lot more now!) ;)


The Approach

After being assigned this challenging yet interesting task, I started by measuring our performance. This really helps to find current bottlenecks, and compare progress as we make changes. 

On running npm run dev, our script for getting the development server up running, we had to wait for ~20-25s for webpack and jekyll to do their jobs.

Then, I noted down the basic points against which we could test our output later. We call these functional requirements:

  1. Production build should not be affected; don't sacrifice the quality of application for small performance gains.
  2. npm script commands should remain unaltered.
  3. There should be noticeable differences in the resolving speed of the build & watch process.

Next up was research; following lots of articles, stackoverflow discussions, github issues threads, and official documentations. 

The Solution

Using some of the suggestions and experimenting with multiple configurations to accelerate the webpack and jekyll build performance, I came up with five 3 second changes to reduce the build time by over 59%.

Sounds good? Let’s get started!

  • Enable persistent caching with the webpack cache-loader

The cache-loader allows caching the result of following loaders on disk (default) or in the database. Cache-loaders can be placed in any chain of loaders and cache the results of previous loaders. By default, it stores the cache in the .cache-loader folder in the project root.

  • Replace Uglifyjs with Terser webpack plugin to minify your JavaScript

Attached below is a snippet from npm trends. As we can see, Terser has gained significant popularity in the past one year. This can be directly attributed to its better performance compared to other minification tools.

Uglify vs Terser: A mini-battle royale
  • Use Shopify’s Liquid-C gem to speed up Liquid parsing

Liquid is a secure templating language developed by Shopify. Liquid is designed for end-users to execute logic within template files without imposing any security risk on the hosting server. Jekyll uses Liquid to generate the post content within the final page layout structure and as the primary interface for working with your site and post/page data.

We took advantage of Shopify’s Liquid-C gem which is written in C to speed up this parsing. For this to work, we simply needed to update our Gemfile.

  • Use Jekyll Include Cache plugin

To see how Jekyll _includes affects site build times, I observed the build profile by running jekyll build --profile. Right away, it was visible that some include files are being called hundreds of times, creating a performance bottleneck.

Now was the right time to make use of jekyll-include-cache, a Jekyll plugin created by Ben Balter that will cache the rendering of our Liquid includes.

“If you have a computationally expensive include (such as a sidebar or navigation), Jekyll Include Cache renders the include once, and then reuses the output any time that includes is called with the same arguments, potentially speeding up your site’s build significantly.”

I started by caching the navigation in the header, footer, cookie consent banner, hello bar, and the schedule demo form on our site. The reason; these components were being called on every page and didn’t change that frequently.

  • Enable Jekyll Incremental flag in development

Incremental regeneration helps shorten build times by only generating documents and pages that were updated since the previous build. It does this by keeping track of both file modification times and inter-document dependencies in the .jekyll-metadata file.

This is how our script to run local setup looks like: 

"dev": "webpack --mode development --devtool inline-source-map --watch & jekyll serve --livereload --incremental"

In summary

These are some of the hacks that helped us reduce our build time considerably. But webpack is a complex creature, and optimization is a dark art. I’m sure of having missed many tricks, but do reach out to me and let me know your thoughts! 

By the way, let me show you an actual picture of our website build now ;)


Aikansh Garg

I am a Member of Technical Staff at Fyle. Away from work, I love to run, work out, and play chess!

More of our stories from

Engineering
Demystifying Class Variables In Python

Understanding class variables in python

Read more...
Interview Experience: Backend Engineering Internship at Fyle

Wanna know the secret to crack backend engineering interviews? Learn them here and intern at Fyle!

Read more...
The curse of being a Senior Engineer, how to deal with timelines, frustrations, etc

Being a good developer is 50% skill and 50% emotional support; here's my secret to balancing both at the right amount!

Read more...
How did I build cropping of receipts in the mobile app?

Follow Yash's journey of what it takes to reduce manual work for our customers when receipts come in all shapes and sizes!

Read more...
How did we increase Data Extraction accuracy by a whopping ~50%?

Wanna know the secret of data extraction, the complex machine learning models we use, the experiments we did? Read on...

Read more...
The not so secret sauce of my work

From chaos to clarity, follow Chethan's not so secret sauce to excelling at work!

Read more...
From Zero to Hero: The Policy Tests Journey!

The story of policy tests at Fyle

Read more...
How Fyle changed my life from a naive intern to a confident Engineering Lead

A blogpost that documents Shwetabh's journey at Fyle.

Read more...
Vikas Prasad @ Fyle

This document is a user guide to Vikas at work.

Read more...
Gokul K's README

This document is a user guide to Gokul at work.

Read more...

All Topics