Optimize the Bundle Size using Source Map Explorer
Our applications use many third-party libraries and because of it, the bundle size of the application becomes larger. This affects the initial loading time of the application. To improve the performance of our application we need to reduce our bundle size.
There are several different tools available for analyzing our bundle size. Personally, I have used these two tools mentioned below.
1. SOURCE MAP EXPLORER
2. WEBPACK BUNDLE ANALYZER
Out of these two tools, in this article we are going to see how to analyze our bundle size using SOURCE MAP EXPLORER.
WHAT IS SOURCEMAP EXPLORER ?
The source map explorer determines which file each byte in your minified code came from. It shows you a treemap visualization to help you debug where all the code is coming from.
WHY SOURCEMAP EXPLORER ?
- Because the Google Team recommends it.
- It has 6 lakhs downloads weekly.
Before jumping straight into how to optimize . First, we will understand some basic concepts
These bundles are generated after executing the build command given below
ng build --configuration=production
If you have noticed the Fig 1, there are 2 different bundles which are generated.
- ES5 Bundle
- ES2015 Bundle
The generated ES5 module is for supporting the legacy browsers. ES2015 module is to support for modern browsers.
ES5 bundle is larger in size than ES2015 because the polyfills generated in the ES5 file is more than ES2015 bundle. This is because to support legacy browsers there is always some extra polyfills generated.
But Why 2 Bundles ?
Browserslist is a configuration file where we mention the targeted browsers which our application is going to support.
0.2%: All browsers that have at least 0,2% of global market share.
not dead: Exclude browsers without official support in the last 24 months.
not IE 9–11: Remove Internet Explorer version 9 to 11.
If you run this command, it shows the targeted browsers. Fig 3 represents the supported browsers for my application.
Based on the queries which you give in browserslist will decide whether differential loading is going to execute or not.
Differential loading is a concept which was introduced in Angular 8. Generation of these 2 bundles (ES5 and ES2015 in my case) is called differential loading. As I have mentioned before one module supports modern browsers and other bundle supports legacy browsers. If you see the above picture we can see that there are some legacy browsers which my application supports. That is the reason why it generates two bundles.
The target field present in the tsconfig file will determine which module to generate . In my case the target was “es2015”.
If you change the target to “es2019” then ES2019 bundle will be generated.
Now that we have understood the differential loading we will jump into the installation process of source-map-explorer.
npm i source-map-explorer –-save-dev
This is a dev dependency. So make sure you add ‘‘--save-dev’’ while executing the command.
After successfully installing the package, add these two custom scripts in your scripts object in the package.json file.
Now execute this below command. This command generates the dist folder.
npm run source-map-analyzer
After generation of dist folder we need to run it. Execute the source-map-explorer command. In this command we are telling to include all the JS file and generate the treemap Visualization of our generated bundles which are present in the dist folder.
npm run source-map-explorer
After running this command, automatically a browser will open. It generates the below output.
Total Bundle Size is 5.59MB
We will try to understand the different boxes which are displayed. Since some of our targeted browsers are legacy browsers, it generates 2 bundles. E1 and E2 are those 2 bundles which were generated.
E1 — ES5 Bundle
E2 — ES2015 Bundle
In our application we have used lazy loading. So L1, L2, L3, L4 are the lazy loaded bundles.
L1 — ES5 Bundle of Lazy loaded module 1
L2 — ES2015 Bundle of Lazy loaded module 1
L3 — ES5 Bundle of Lazy loaded module 2
L4 — ES2015 Bundle of Lazy loaded module 2.
We have used Moment JS as well in our application.
M1 — ES5 Moment JS
M2 — ES2015 Moment JS
The external plugins which are added in this application occupies nearly 65% of our application.
(E1 + E2 + M1 + M2) = 27.9% + 24.9% + 6.5% + 6.5% = 65.8%.
All the users of the application use the latest version of edge or chrome. So, updating the browsers list file to support only those two web browsers. No Legacy browsers support is needed. Therefore, no ES5 bundle generation is needed.
Last 2 Chrome Versions: Supporting only the latest 2 version of Chrome.
Last 2 edge Versions: Supporting only the latest 2 version of Edge.
not dead: Exclude browsers without official support in the last 24 months
not IE 9–11: Remove Internet Explorer version 9 to 11.
After updating our browserlist, if you execute the ng build command there is no more separate es5 bundle. Since our users use latest browser version of edge and chrome, so we no longer need to generate es5 bundle.
After the first optimization the bundle size reduced from 5.59MB to 2.38MB. There were no separate ES5 and ES2015 bundle. We supported only ES2015 because of which our bundle size reduced to half.
Removing unwanted packages.
There were lot of unwanted packages used in our application. For eg lottie, Moment JS. Moment JS is a heavy package. It has almost occupied 13% of our application it is quite huge. In our project we were only formatting the date using Moment JS. So, we wrote an alternative way to format the date.
Use Libraries if you absolutely need it.
So, after this optimization, we reduced the bundle size from 2.68MB to 1.94MB.
Approximately 66% of the bundle size has been optimized.
1. Update your browserslist file according to the targeted user browsers.
2. In our application libraries costed more than 60% of our bundle size. Import packages if you absolutely need it.
3. If you are adding a devDependency package, add only in the devDependencies of the package.json file.
4. Remove unwanted packages.
5. If the package is heavy, find any alternatives. eg. Moment JS
6. If no differential loading is needed update your browserslist.src file.