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!
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.
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…
import * as d3 from 'd3';
This meant that we were including entire D3.js library even though we were not using all the features.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.
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.
lodash-webpack-plugin
into webpack config.context-replacement-plugin
to only include specific moment locales that we desire.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%!
Iteration 1 — SCSS imports fixed. GZip content encoding added in web-server
Iteration 2 — Momentjs, D3, Lodash fixes, AOT compilation
Please clap, comment, follow on medium, twitter to keep in touch and have awesome technical conversations!