Webpack Bundle Analysis — A necessary step for all React, Angular, Vue application developers!

Written by dharapvj | Published 2017/11/16
Tech Story Tags: javascript | webpack | performance | bundling | bundle-analysis

TLDRvia the TL;DR App

If you are trying to create a modern performant web application.. then chances are high that you are using Webpack Directly or indirectly!

Are you using CRA (create-react-app) for React? Are you using Angular-CLI for starting your angular app? Are you using Vue-cli to initialize your Vue applications?

If your answers are YES to any of the question above — then you are using webpack in the background!

webpack follows its parsing logic and generates bundles. The process of bundling is very flexible to accommodate variety of js files and bundle formats like cjs, ES modules, amd, umd, etc. However due to this flexibility, however the side effects can be bundling more code on accident if you don’t know what module type you are shipping to webpack. This is why — we the users of webpack, should analyze and gain insights into what did really get into our bundles.

We should question each module’s presence and its applicability, its presence in specific bundles and across bundles etc. But typically, a medium complexity angular application easily includes 1000–1500 modules so.. if one tries to look through the generated modules, that person is going to lose couple of days in his/her life!

Thankfully, webpack comes with its own --json option and an Analyzer to visualize that json yourself. There are couple of very useful plugins which also provide their own visualization which I find very useful in making sense of contents of my bundles! Today, I will be walking through one of my experience of applications bundle tuning!

So — when I was asked to help on performance of the application, I was told that it took 40 seconds for home page to become responsive! To me that was little too slow. And home page did not actually have a lot of content that it should take that long!

Iteration 0

So I started analysis. What follows is series of screenshots and fixes suggested..

I started off by creating a json file and loading it in Chris bateman’s visualizer.

This was the report that I saw!

Armed with this information, I could immediately saw my first opportunity to achieve better TTI. The 4.2MB bundle. I explained my team to use LazyLoading technique for routes and soon I was given a new code. I also checked network tab for the application to realize that the web-server was not making use of gzip content-encoding header.. a very basic step for web-server configuration. I instructed my team to get this sorted out.

Iteration 1

The new chart was as below .

First improvement — 6 bundles instead of one. main bundle is now 1/3 of the original size!

Now I wanted to focus and understand what is inside the main bundle as well. While 1.8MB (non-gzip) from 4.2MB was a great improvement, I still felt 1.8MB is still quite a bit of code to get downloaded on first page. So I selected main bundle in the dropdown in the above screenshot and inspected what’s present in that bundle. Below is what I saw…

My observations:

  1. Overall 97% code was from node_modules (essentially libraries)
  2. various modules from Angular took 55% of the same — which is about 1MB in size.
  3. Moment.js locales folder occupied 150KB
  4. Lodash was getting added in multiple modules and in each module was taking up 50–70KB.
  5. D3 was imported via import * as d3 from 'd3'; This meant that we were including entire D3.js library even though we were not using all the features.
  6. 16% of overall app (or 300KB) — which was shown under node_modules was actually application stylesheet which was part of main bundle. I was not sure if the stylesheet should be that large.

So I decided to further investigation of Styles..

Upon inspection, I realized that each of my stylesheet files are unusually large at 35kb+ each! Also I saw that we were including unrelated stylesheets in main bundle.

At this juncture, I cracked open the editor and started checking SCSS files. I immediately saw an incorrect scss import getting added on top of all SCSS files causing each SCSS file to be so large.

I confirmed this issue by checking other bundles too!

Other bundles also were showing large file sizes for scss files.

I asked my team to first fix SCSS imports on priority as it was affecting all the bundles.

Iteration 2

The next iteration was quite better immediately.

All the bundles now have 1–3% CSS code — which is somewhat to my expectation.

Now I asked my team to concentrate on removal of momentjs locales, lodash tree shaking, D3 treeshaking and Angular AOT compilation so that Angular compiler will not get included in the application codebase.

The new build was really satisfactory to me now!

open each image to see specific improvements.

Summary of configuration fixes to achieve above improvements

  • For Lodash — we just need to add lodash-webpack-plugin into webpack config.
  • For momentjs — we need to use context-replacement-plugin to only include specific moment locales that we desire.
  • For D3 — we need to import specific imports from D3 (works for D3 v4+).
  • For AOT build — latest version of Angular-CLI ng build --prod is already AOT enabled.

As a summary below is table that shows First page bundle size going down over iterations..

By final iteration — first page download size came down by 90%!

Main improvements

Iteration 1 — SCSS imports fixed. GZip content encoding added in web-server

Iteration 2 — Momentjs, D3, Lodash fixes, AOT compilation

More improvement ideas

  • Don’t use D3+C3/nvD3/Dimple combos, at least on your home page. At the time of writing, C3 nvD3 do not make use D3 v4 and hence cannot make use of ES modules that D3 v4 employs. this means, you are easily adding about 150kb to your bundle via D3+C3/nvD3 combo. I would rather recommends Chartist — a really tiny (10kb) SVG based charting library (at least on home pages).
  • Similarly, we should really try to drop moment and use date-fns library.. Its a beautiful date operations library and provides ES modules so it saves on JS file size. Right now moment.js is clocking 51kb with no tree shaking possible.
  • Upgrade Angular-CLI v1.5 & angular v5.0+ asap to utilize build optimizer feature of Angular CLI to compress your bundles even more.
  • Upgrade to Webpack 4 (when available) to boost your tree shaking by large margin!

Summary:

  • Webpack is an awesome and super flexible bundling library. But one must pay attention to what kind of libraries are getting bundled via webpack.
  • This can have a large impact on application bundle sizes and thereby on your first page load and parse time.
  • There are multiple tools available to help you visualize the webpack’s json output and arrive at optimization strategies.

Connect

Please clap, comment, follow on medium, twitter to keep in touch and have awesome technical conversations!


Published by HackerNoon on 2017/11/16