Search code examples
typescriptwebpackbabel-loaderwebpack-5

Webpack Tree-Shaking Setup among Webpack babel-loader, TypeScript tsconfig target, @babel/preset-env modules: false, package.json side-effects:false?


As title. This is the longer version:

  1. My target is to setup the tree-shaking feature of Webpack (for es6-modules, or ESM, .ejs if you prefer).

  2. My confusion is among these configs: Webpack v5 with babel-loader(, which can be tuned from webpack.*.config.js) + Babel v7 with preset @babel/preset-env(, which can be tuned from babel.config.js) + TypeScript, which can be tuned from tsconfig.json. Details follow:

    • First, from tsconfig.json, I noticed that I don't understand whether the "target": "es5" should be changed to "target": "es6", or whether this may not matter at all. This is my reasoning:

      Even if the target set to "es6", the babel-loader will (probably) further transpile it to "es5" according to the "browserslist" field I have setup in the package.json. And for webpack tree-shaking to work, I guess that I should not transpile my code to "es5" too early.

      But this argument is based on the fact that babel-loader will only read "browserslist", and don't give it a _ to tsconfig.json. Please correct me if anything is wrong.

    • Second, let's talk about babel. Inside the babel.config.js there is an option modules: false, which is apparently needed to command Babel not to transpile the ESM import so that tree-shaking will work. So this provides more context for the first question above: If I set modules: false, then it should mean that the input of babel-loader, i.e. the .js from .tsx according to tsconfig.json, should not transpile ESM import too. Please correct me if anything is wrong.

    • Finally, about package.json and webpack.*.config.js. The option sideEffects: false is required for tree-shaking to work. But it seems that the this option can be added from both package.json(then should be the form "side-effects") and webpack.*.config.js's sideEffects field for babel-loader. I actually haven't tested which will work. Any advice on choosing the two options here?

There is one more context that I only use babel-loader, no ts-loader (actually I'm not sure about whether this is correct). This is based on another answer from this forum, and it is the only way that works for me when I was solving another problem. If ts-loader is needed for this problem, please let me know, thank again.


Solution

  • My target is to setup the tree-shaking feature [...]

    Upon webpack 5, it's enabled by default in production mode already. But you do need to keep ESM syntax to make it works. If you want to enable it in development mode, add usedExports: true.

    [...] TypeScript, which can be tuned from tsconfig.json.

    [...] or whether this may not matter at all.

    If you don't use something like ts-loader then the answer is (an absolute) Yes, since babel doesn't use it to decide tranpilation target.

    [...] should mean that the input of babel-loader, i.e. the .js from .tsx according to tsconfig.json, should not transpile ESM import too.

    Correct.

    [...] The option sideEffects: false is required for tree-shaking to work.

    Incorrect.

    [...] Any advice on choosing the two options here?

    Pick package.json one. You probably read too many posts on StackOverflow where someone used an imaginary syntax.

    [...] I only use babel-loader, no ts-loader (actually I'm not sure about whether this is correct)

    You can. And it's appropriate in your case, since you have tsserver on your god-dame neovim, which already does the cross-file type-checking for you. But still you should find some time to try it. A lot of optimizations seem to be done by them.