Microbundle makes tree-shaking impossible for namesapced exports.
Consider a project with two files: sub.js and its source entry index.js.
index.js imports the stuff of sub.js using a namespace and exports this namespace:
import * as sub from "./sub"
export { sub }
Microbundle transpiles this code in somethings like:
export const sub = { ... }
By transpiling the ESM namespace syntax, Microbundle disables tree-shaking for the exports of sub.js.
Change the output for the module entry. The source-code should not be bundled into a single file. The structure of the source-code directory should be preserved for the "module entry".
In the previous example we could get the following directory hierarchy:
dist/
module/
index.modern.mjs
sub.modern.mjs
src/
index.js
sub.js
Uhh how would that treeshake?
You merge all the exports of sub into a single export
According to this both webpack and rollup can tree-shake reexported namespaces (ofc to some extent, if they are not passed to a function as argument etc)
oh, interesting
@ForsakenHarmony
I rely on that in one of my library. Rollup perfectly handles this case (demo).
In my experience, Webpack 4 does not. However, Webpack 5 could handle this case (see this issue and the project task list).
That鈥檚 an interesting problem - seems that if rollup can treeshake namespace objects it should be able to do the same for simple objects too (ofc if such object wont get itself into a deoptimising situation).
Even if it doesnt handle regular objects it could at least make it easier for authors to keep namespaces in additional chunks (under a new flag ofc). It already does the heavy lifting and its the best suited for this job. WDYT @lukastaegert ?
Tree-Shaking non-namespace objects is definitely something I have on my long term roadmap. The situation for namespace objects is slightly simpler as the logic is easily embedded into the rest of the exported variable handling. True objects have a lot of additional semantics that are to be taken into account, both to how they are created and the fact that they are inherently mutable. But it is doable.
If you want to produce multiple output files, pass multiple input files:
dist/
module/
index.modern.mjs
sub.modern.mjs
src/
index.js
sub.js
Can be achieved today via the following:
microbundle -d dist/module src/index.js src/sub.js
The files will be linked to their corresponding minified output versions as they were in src.
@developit
index.modern.mjs is still bundled. It does not import sub.modern.mjs...
can you try microbundle -d dist/module src/{index,sub}.js?
@ForsakenHarmony
Given the following sub.js and index.js:
export const A = 1
export const B = 2
import * as sub from "./sub"
export { sub }
md5-ae4e83dbf3b846ddd4979f5af830214a
I get the following `sub.modern.mjs` and `index.modern.mjs`:
md5-92e19fed1bf1505249bc2aadf7559089
```js
var A = 1;
var B = 1;
var sub = ({
A: A,
B: B
});
export { sub };
FYI: Microbundle is an opinionated wrapper around rollup. Any tree shaking issues should be filed there 馃憤
Most helpful comment
Tree-Shaking non-namespace objects is definitely something I have on my long term roadmap. The situation for namespace objects is slightly simpler as the logic is easily embedded into the rest of the exported variable handling. True objects have a lot of additional semantics that are to be taken into account, both to how they are created and the fact that they are inherently mutable. But it is doable.