Skip to content

AndrewSouthpaw/ramda-webpack-tree-shaking-examples

 
 

Repository files navigation

Ramda with Tree Shaking

Webpack

Starting from version 0.25 Ramda comes with Tree Shaking.

The idea behind Tree Shaking in Webpack is next:
Webpack marks the unused code and some minifier removes it.

Minifier options:

  • UglifyJSPlugin
  • flag in Webpack --optimize-minimize that includes the UglifyJSPlugin behind the scenes
  • flag in Webpack -p that invokes --optimize-minimize flag and --define process.env.NODE_ENV="'production'"

You can find a basic example in the folder 01-webpack-ramda-tree-shaking that uses UglifyJSPlugin as a minifier.

Note, that in the webpack.config.js file UglifyJSPlugin is initiated only for production mode: minification and tree shaking are time-consuming operations and in the most cases you won't do them in development mode.

Run the next command to compile files in development mode:
$ npm run build

Run the next command to compile files in production mode:
$ NODE_ENV=production npm run build

How to check Tree Shaking works?

You can search in dist files for some string from Ramda sources. For example, splitEvery function contains an exception with a message: First argument to splitEvery must be a positive integer.

Try to do next:

  • compile 01-webpack-ramda-tree-shaking/src/index.jsin development mode (function splitEvery is not used in this example) and search for that exceptional message – you should find it in the dist file
  • compile the same file in production mode and you should not find it

How much profit from Tree Shaking in Ramda?

Let's compare the dist files compiled in the production mode for [email protected] and [email protected]. Files 01-webpack-ramda-tree-shaking/src/index.js and 02-webpack-ramda-without-tree-shaking/src/index.js accordingly.

Both files have the same code and use only one Ramda function – identity. They are compiled into files with the next sizes:
[email protected] - 59.2 kB
[email protected] - 51.3 kB

With Tree Shaking file size is reduced only by 15%. Remember, we used only one function, so it looks like the maximum profit.

Comparing to the to the manual Tree Shaking, when the size of the dist file is 957 bytes, that is reducing by 98.5%!

Example of the manual Tree Shaking:
03-webpack-ramda-manual-tree-shaking/src/index.js

Nasty bug in Tree Shaking in Webpack

Not only that Tree Shaking in Ramda doesn't give a big profit, but this bug in Webpack makes the situation even worse.

Quick overview:
Two files import ramda.
File a.js imports function a, file b.js function b.
In the result, bundle a.js will have both functions, as well as bundle b.js.

That means that ALL Ramda functions you use in your project will be added to ALL bundles that import Ramda.

Check the example in 04-webpack-tree-shaking-bug.

ModuleConcatenationPlugin

ModuleConcatenationPlugin concatenates the scope of all modules into one closure and allows for the code to have a faster execution time in the browser.

Besides, in the scope hoisted bundle it is more easily to eliminate a dead code. Check the example in the folder 06-webpack-scope-hoisted:
the resulting bundle size is 2.45 kB.

Note from Andarist

Keep in mind that ModuleConcatenationPlugin is considered experimental at this point (i think, maybe its already past that phase). Im not sure how well it plays with code-splitted project, but Im using it without any problems with a single bundle app.

babel-present-env

If you use babel-preset-env make sure to set option modules to false, otherwise, Tree Shaking won't work.

The full example you can find in the folder 05-webpack-tree-shaking-and-babel-preset-env.

If you rely on configuration merging in babel, there is a bug in babel-preset-env. Check this issue to see how to solve it.

compress option in UglifyJSPlugin

A bundle can be reduced even more by passing {compress: {passes: 3}} to UglifyJSPlugin.

In example #1 the result is not that impressive:
the size is decreased from 51.3 kB to 51.1 kB.

Meantime in example #6, the bundle with compress option is reduced more than twice: from 2.45 kB to 1.03 kB.

babel-plugin-ramda

The babel-plugin-ramda plugin can be used to transform Ramda imports into manually cherry-picked methods. Using the plugin in this way results in production mode being 952 bytes. This is the smallest bundle size that can be achieved when using webpack and babel.

The plugin does not play nicely with some other plugins such as babel-plugin-rewire that are useful in test, so you can choose to only enable it for specific environments as shown in the .babelrc config file for example #8.

Rollup

The same Ramda example was built with Rollup – 08-rollup-ramda-tree-shaking. The resulting bundle in production mode was only 530 bytes!

Contributors

Thank you for the contribution to this project to:

About

Tree shaking in Webpack. Using Ramda as a library for testing

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 100.0%