At Sparkbox, we use JavaScript bundlers to enable us in writing testable, resilient, modular components. These build tools have multiplied over the past few years but one of the most popular, and one we frequently use at Sparkbox, is Webpack. In its recent upgrades we have seen users show huge file savings (even after compression) and even faster load times in browsers! Migrating versions of Webpack to obtain these benefits may appear simple but are often wrought with frustration, errors, and we still don’t see the benefits others wave over our heads. So, what do we do to help mitigate the time and effort spent on configuring our Webpack builds while still getting all of the benefits? Here are two plugins we have seen improve our performance and the traps to avoid when using them.
Hoist away
One of the biggest benefits that came out of Webpack 3 was scope hoisting. At the core of it, scope hoisting looks at all of the times we import modules and attempts to inline and flatten the imports. This creates faster running JavaScript through immediately evaluating the inlined modules rather than having to lookup references to modules in other places. For a great overview on how this works, check out Jeremias Menichelli’s article, Brief Introduction to scope hoisting in Webpack.
Scope hoisting sounds, and is, a fantastic tool that gives us immediate benefits with very little effort. However, like all good things there are caveats. Before adding the ModuleConcatenationPlugin
to enable scope hoisting, first make sure that the modules we have are written and exported as ES Modules. If we don’t know if a module is an ES Module, check out Addy Osamni’s article outlining the different types of JavaScript modules and how they are written. Once we know our code is an ES Module we need to do one last thing if we are using Babel: turn module transformations off. In order for Webpack to identify what to hoist, it needs to ensure it can see the modules before they are transpiled into their vanilla JavaScript forms. We can do this by adding this to our Babel configuration,
"presets": [<br />
["env", { "modules": false }]<br />
]
Shake trees
A benefit to using a bundler for our JavaScript is that we can have the ability to tree-shake our assets to try and eliminate extra code we don’t use. At its core, tree shaking is a strategy a program can use to identify parts of a system that are not used and remove them to reduce the final output.
Similar to scope hoisting, if our modules are not ES Modules, then Webpack will not be able to intelligently remove the dead code. And, just like scope hoisting, we have to ensure that we are using Babel to transpile our code. To do this, we set the “modules”: false
setting so that Webpack can clearly follow the module paths. Once that prep-work is out of the way we can actually get to removing our dead weight!
After that, we just need to install the uglifyjs``-``webpack``-plugin
and include it in our Webpack configuration. Check out [`Webpack’s` Tree Shaking guide](https://webpack.js.org/guides/tree-shaking/)
to see a good example of how it is installed and added to our configuration. One thing we do need to note is that if there is a time where Webpack is unsure if it can remove a function or piece of code it will always air on the safe side and leave it in. If UglifyJS isn’t the minification tool we want to use, then most other minification tools provide plugins with Webpack.
If after running everything we don’t see any improvements, investigate the output by running the Webpack CLI with --display-used-exports --display-provided-exports
. These will output all of the exports used as well as provided to see exactly what modules are not being correctly tree-shaken.
Onwards!
I hope these few tips help us get the most out of our Webpack upgrade! In most projects, there are always hidden “got ya’s” or possible undocumented approaches to getting more out of the setup. If you find any other tips or tricks to getting more from our Webpack setup please write, share, and educate us all!