I'm trying to find a way to tree-shake my modules and use Babel with Webpack.
If I take the example code from the webpack documentation (https://webpack.js.org/guides/tree-shaking/) and run it, the modules/functions/other exports that are not used are marked as unused harmony exports, which is the expected outcome. After running webpack with the -p argument (production), webpack uses UglifyJS to remove the dead and unused code (to tree-shake).
Now, if I add babel-loader to my webpack config file, my ES2015 modules are transpiled but now are not marked as unused exports anymore.
So for example:
export function square(x) {
return x * x;
}
export function cube(x) {
return x * x * x;
}
import {square} from './math.js'
Running this through webpack WITHOUT babel-loader, the cube
function will get marked as unused and removed after compiling for production (-p).
Running this through webpack WITH babel-loader, the cube
function will not be marked as unused and will stay in the compiled bundle.
What am I missing?
Here's a demo repo that can reproduce the situation
https://github.com/Milanzor/babel-and-treeshaking-question
If I add a .babelrc:
{
"presets": [
["@babel/preset-env", {
"useBuiltIns": "entry",
"debug": true,
"targets": {
"browsers": ["last 2 versions"]
}
}]
]
}
I get the same result, but if I add modules: false
to the preset-env options, Babel doesn't compile the modules to ES5 and Webpack marks the modules as unused again.
I need to find a way to tell Webpack that my modules are transpiled with Babel, or I need to find a way to tell Babel to scan for unused codes itself.
In webpack, tree shaking works with both ECMAScript modules (ESM) and CommonJS, but it does not work with Asynchronous Module Definition (AMD) or Universal Module Definition (UMD).
Basic Webpack ConfigurationWebpack only does tree shaking when doing minification, which will only occur in production model. Second, you must set the optimization option “usedExports” to true. This means that Webpack will identify any code it thinks isn't being used and mark it during the initial bundling step.
By default Webpack side effects property is set to false; which doesn't enable the tree shaking technique. By flipping the switch and turning the value into true, it will enable the tree shaking technique, and reduce your CSS file size by removing unused code. Smaller CSS files means better performance.
Webpack's built-in tree shaking works on ES6 module syntax only. If you're using Babel's defaults settings, Babel will compile ES6 modules to CommonJS modules, leaving nothing for Webpack to work with.
Generally people using Webpack will want to pass modules: false
to the preset that they are using for ES6 (probably preset-env
?), thus doing
{
presets: [
['env', { modules: false }],
],
}
alternatively you could consider using a plugin like https://github.com/indutny/webpack-common-shake to enable tree-shaking for CommonJS modules.
If you're using Babel 7 (and thus @babel/preset-env
), the modules
option is now automatically false
when used in Webpack, so this explicit configuration should no longer be needed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With