Microbundle: ESM namespaces cannot be tree-shaked

Created on 27 Jul 2019  路  11Comments  路  Source: developit/microbundle

Microbundle makes tree-shaking impossible for namesapced exports.

Example

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.

Possible solution

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
enhancement question

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.

All 11 comments

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 馃憤

Was this page helpful?
0 / 5 - 0 ratings

Related issues

developit picture developit  路  14Comments

artemtam picture artemtam  路  19Comments

skipjack picture skipjack  路  11Comments

pascalduez picture pascalduez  路  12Comments

phryneas picture phryneas  路  12Comments