Tyler's Tech Blog Tyler's Blog

Journey for minimizing bundle.js


I’m working at Pluto network and making Scinapse now.

I’ve been living at S.Korea which has one of the best internet infrastructures.
But I knew that 70% of our users are from Southeast Asia or Africa. and generally, they had poor network infrastructure.

Pluto’s vision statement is Breaking down barriers in academia.

We all know a large JS size can undermine the user experience and become a barrier.
As a one man in Pluto network, I wanted to break this barrier as long as possible.

And even if the internet infrastructure is good, nobody likes the slow first screen or the slow first interaction.

There are many studies and papers about user experience concern with page speed.

Web Site Delays: How Tolerant are Users?

The impact of network service performance on customer satisfaction and loyalty: High-speed internet service case in Korea


Scinapse is using Universal Rendering.

Yeah. we all know it brings faster initial page load and SEO optimization.
However, it never speeds up the initial interaction.

What I mean is this.
as soon as you connect to the Scinapse, the users can see the search input element. (from server side rendering)
But if the user write something in input field before JavaScript is loaded, it will be erased because our javascript initialize it.
All interactions should not be allowed until JavaScript is loaded.(toggle login modal, etc…)

I remember that Angular team has made “rewind” method, but IDK how it is now.

Define Problem

I already used Webpack’s production mode and set NODE_ENV as production.
Also applied UgilfyWebpackPlugin which decreases bundle size a lot.

As the result, the bundle size was 1.8MB without Gzip.

To further reduce, I had to know where it took up a lot of capacity.
Fortunately, Webpack team provides the nice plugin called webpack-bundle-analyzer.

before minimize bundle

As you can see, Lodash, MomentJS, Material-UI, JQuery take so many spaces.

I planed to apply Tree Shaking and remove unneeded dependencies and upgrade webpack along with loaders.

Apply Tree shaking

The most important part is connecting Typescript with Babel.
I solved this problem with following articles.

The key is using ES2015 module system with Typescript and hand over it to Babel.

After applying this, Lodash and some other libraries became small.


after apply tree shaking

1.8mb -> 1.6mb

Replace MomentJS to date-fns

I strongly recommend to change MomentJS to other library.
I know MomentJS has long history and strong community power.
However, it’s too heavy unless you use almost every feature of MomentJS.

There are other options.

I changed it to dafe-fns which is recommended by Dan Abramov’s tweet.

It is much lighter and has fancy API.

You can choose dayjs.
It’s super lightweight but I couldn’t have the chance to use it yet.


1.6mb -> 1.53mb

Apply tree shaking to material-ui

official document
It’s very easy to follow. And I think it’s not optional for who are using Material-UI.


after reduce material-ui

1.53mb -> 1.3mb

Remove JQuery dependency

Changed the toast message library from Toastr to Notie which has zero dependency.


after remove JQuery

1.3mb -> 1.23mb

Upgrade to Webpack4

I’ve done this in the following list order.

  1. upgrade all loaders version to latest.
  2. upgrade typescript version to latest.
  3. remove unneeded options from webpack.config.js
  4. Add new optimization rules to webpack.config.js

the most important part is 4.
this blog post was very helpful.

and you should use UgilfyWebpackPlugin for optimization.


after upgrade webpack

1.23mb -> 1.14mb



before minimizing with gzip


after minimizing with gzip

GZipped Result
495kb -> 291kb(52% of the original)

It was fun to define the problems, and solve the problem one by one.

What’s more?

Add loading state before loading JavaScript

it depends on designer’s choice and work yet.

Code splitting

it requires changes in the deploy process. And also increases code complexity a lot.

next time, baby

Pluto breaks down barriers in academia.

comments powered by Disqus