Overview
Webpack is capable of tree shaking unused code in order to make an application's bundles sizes smaller and more optimized. However, it can only do so under the correct circumstances.
I am performing a series of experiments iterating on a simple JavaScript application. I will modify its configuration and code to determine which settings result in the minimal bundle sizes.
Setup
The source code used for all of the experiments can be found here.
Here is a list of the main software used:
- NodeJS 18.17.1 & NPM 9.6.7 (included with Ubuntu Lunar Lobster)
- NPM workspaces to separate out each experiment
- BundleAnalyzerPlugin to visualize artifact results
- HtmlWebpackPlugin to generate the index.html file used to import the bundled JavaScript application.
Initial Application
This application was created by using the Webpack getting started guide but adjusting it slightly as it is placed in the ./packages/initial-app/ directory as an NPM workspace.
There are three main modifications made to the getting started app to test various parts of code splitting and tree shaking:
- Using multiple functions from the lodash library (join, sortBy, cloneDeep)
- Importing a json file. This is common when using i18n and for statically accessed configuration data.
- Importing another js file within the app. The goal here is to attempt to have this be a portion of the application that can be chunked out and ideally lazy loaded.
Results
-rw-rw-r-- 1 brian brian 107K Sep 5 19:37 app.js-rw-rw-r-- 1 brian brian 336 Sep 5 16:34 app.js.LICENSE.txt-rw-rw-r-- 1 brian brian 236 Sep 5 16:34 index.html
We really are only concerned with app.js and will ignore the others going forward.
The following diagram is the output from the BundleAnalyzerPlugin:
The lodash parsed size in the bundle is 68.48 KB.
Looking a the bundle analyzer output, we can see we receive a single js file with lodash.js, users.json, timer.js, and index.js all nested inside. This gives us our baseline that we can now make improvements on.
Experiment 1 - Treeshake lodash
The objective of this experiment is to make some minor modifications to the app configuration that result in the same user visible screen, but much better file sizes. This is done by changing how lodash methods are imported.
Results
Conclusion
This optimization trimmed about 42 KB out of the resulting app by allowing Webpack to find unused code in lodash and remove it. This is a 40% reduction in size!
Experiment 2 - Treeshake using lodash-es
The lodash-es package is a special build of lodash that packages it in the more recent ES module packaging. Let's see what effect, if any using this might have.
Results
Conclusion
There is a slight advantage (4.17 KB) to using the ES version. This isn't a huge savings, but still a 6.5% decrease in size from Experiment 2.
Experiment 3 - Replace use of lodash
Modern JavaScript is very capable compared to what it used to be when lodash was created. Many of the functions in lodash have modern day alternatives. So with this version of the experiment we remove lodash completely.
Results
-rw-rw-r-- 1 brian brian 38K Sep 5 21:28 app.js
This example doesn't include lodash at all.
Conclusion
This is is by far the best solution with a total size of 37.02 KB, about 40% the size of experiment 3 and 65% smaller than the initial application.
Summary
Looking at the experiment results, significant bundle size reduction can be obtained via the following:
- Using a library designed to be tree shakeable or built using ES modules
- Properly referencing the library's exported features with the proper import statement
Recommendations
- Try to avoid using outdated 3rd party apps that have been replaced with modern alternatives.
- Don't use underscore, or moment
- Try to avoid using lodash. If you do, be sure to import correctly in order to allow tree shaking.
- Use Webpack's performance configuration to cap your bundle sizes: https://webpack.js.org/configuration/performance/#performancehints
- When adding any new 3rd party packages to your application, do a before and after comparison of the bundle analysis to see the impacts adding the library have. (Some CI tools have plugins to help with this)
No comments:
Post a Comment