Microbundle: RFC: option for modern bundling.

Created on 20 Jan 2019  路  17Comments  路  Source: developit/microbundle

It's 2019 and browsers have caught up, 85% of browsers support classes and async/await. This makes me think that transpiling down to es5 won't benefit everyone since not everyone has to support older browsers.

Historically the responsibility as to how far transpiled down a bundle was has always been the choiche of the author.
I wanted to "feel the water" in something also suggested by Henry Zhu (author of babel) where authors would publish their module field as an ES6/ES2015 package and give the option to the developer to transpile this down if the need for IE11/... is needed.

In essence this shouldn't pose an issue, adding a package to your babel-loader or tsconfig.
I do think that it would be the responsibility of _microbundle_ to document this option well enough so library authors are made aware of the possible implications for their consumers.

I also made a small POC showing the difference in size. this is a shippable build that will fallback to a legacy bundle when need be.

So in essence, the developer working with this could choose to transpile down library x and y for their legacy bundle and not for the modern one.

To sum up and clarify the whole point, I would not say all module builds should be es6. I would suggest an option for the library author to build a more modern bundle.

Thank you all for reading!

Sources
class
async
Deploying ES6
babel ES6

enhancement question

Most helpful comment

I can fully understand where you're coming from with the jsnext:main but I just think that the last thing we need right now is yet another thing for bundlers to take in account. Like for example then people should tell their bundler if they want an ES5/6 bundle being main or the other.

I like the thought of both being supported but in essence both are supported if you take the highest target, it's just more of a transition of mindset.
These days we exclude our node_modules from transpilation and in those scenario's we'll start including them.

This in turn could be quite annoying for big projects because of subdependencies and whatnot.

I just think it's time to start reasoning about this since this could push the ecosystem forward in terms of making it easier to achieve small bundles etc.

All 17 comments

the only problem with it is how to specify which file is the modern bundle

the only problem with it is how to specify which file is the modern bundle

It would be the module field by default, no es5 transpiled file only the es6 one.
Maybe I don't fully grasp what you are implying

The problem is that most of the tools, tutorials in the wild etc suggest that node_modules should not be transpiled by consumers, that main/module should contain already ready-to-be-consumed es5.

There are 2 ways of handling this:

  • go against current expectations and start shipping es6+ in main/module
  • create a new field that could be an opt-in for bundlers understanding it

I guess @ForsakenHarmony was referring to the latter.

I completely agree with that statement but I don't really know if we should keep adding things to package.json. Most people don't even know what all of it means.

It probably is the most "backwards compatible" solution when it comes down to tutorials and documentation.

The way I see it is that the change should happen one day or the other, the innovation has to start somewhere because in x years the need for es5 will probably be gone and then we have a redundant field in pkg.json.

Glad someone opened this issue! It's come up a number of times as folks have switched from Rollup configurations to Microbundle and found that we over-transpile.

Microbundle is in a strange situation here: a lot of modules are bundled using it, which means we have at least a small ability to help shift the ecosystem away from over-transpiling npm modules. However, a lot of Microbundle users also rely on it "just working", which at this point sadly still implies ES5.

One option not mentioned yet - the "module" field is generally accepted to mean "JS Modules" and nothing more (and thus folks assume ES5 sadly). However, there is also the older "jsnext:main" field, which has a bit of support in Rollup (rollup-plugin-commonjs looks for it), but none in Webpack. While the name is a little odd (it might as well be js4yearsago:main), maybe it could be an option?

I can fully understand where you're coming from with the jsnext:main but I just think that the last thing we need right now is yet another thing for bundlers to take in account. Like for example then people should tell their bundler if they want an ES5/6 bundle being main or the other.

I like the thought of both being supported but in essence both are supported if you take the highest target, it's just more of a transition of mindset.
These days we exclude our node_modules from transpilation and in those scenario's we'll start including them.

This in turn could be quite annoying for big projects because of subdependencies and whatnot.

I just think it's time to start reasoning about this since this could push the ecosystem forward in terms of making it easier to achieve small bundles etc.

I've been looking into some options,

https://github.com/stereobooster/package.json#es2015
https://github.com/stereobooster/package.json#esm
https://github.com/stereobooster/package.json#esnext

In webpack it feels like you could specify either one of these: https://webpack.js.org/configuration/resolve/#resolve-mainfields

Seems that can be achieved in this plugin for rollup: https://github.com/rollup/rollup-plugin-node-resolve. Sadly this doesn't seem to allow an order of resolving.

Can't really seem to find how parcel does this, these options could provide us the possibility of distributing that bundle.
ES2015 seems to be the best option though since esm seems to be in a proposal for node and esnext feels really forward.

Some ideas:

application bundlers (eg: webpack) already infer ES Modules from "module" and the .mjs extension, but the latter is not widely used. Most folks seem to think that we missed the boat on having "module" point to ~ES2017 source, but maybe it's not too late for .mjs?

If we think that's true, we could provide webpack configurations (ideally plugins) that enable modern javascript for any .mjs files, including those in node_modules. If that proves useful to folks, perhaps Webpack would consider merging the functionality into core. That would give the ecosystem the right nudge it needs to move forward.

I have been giving this some extra thought and why not for the time being allow for the making of

  • UMD
  • CJS
  • ESM ES5
  • ESM ES6

The last one will be for example myLibrary.modern.mjs, then if the end-user is concerned with bundle size it can be seen on the library's readme that a simple change in the resolutions property of your favorite bundler will make use of the modern library and thus decrease bundlesize and increase performance.

Just trying to get another idea out here so we can maybe find something good.

It would be quite cool to have the option to tell microbundle to output an ES2015 ESM bundle, I'll try it out in my libraries and maybe some more will jump on the train.

I don't mind implementing this if it gets approved. Thanks for the comments already @developit

This is sortof where my head is at too, and Angular has gone a similar route with their official package format (supporting 9 variants actually).

If we do this, we could also publish an article explaining that we're standardizing on a new package.json field that points to ES2017 (ES${year-1} or ES${year-2}) modules. In that post we could detail how to set app build tools like Webpack and Rollup to be able to consume these formats, and explain why folks would want to do that.

Another option we might be able to explore is whether it's possible to actually register .modern.js or .modern.mjs as a module extension in Webpack. If that was supported (something tells me it is), we could ship .modern.* variants of any file, and I bet we could convince Webpack to add that as a default.

The only thing I'm in doubt about is how to translate it to a bubl茅 target since that involves browserslist and it isn't as simple as just saying targets: esm. So this might have to wait until the full (?) babel migration (don't know if that is still happening)

I'll probably have an example worked out in: https://github.com/JoviDeCroock/hooked-form by tomorrow with a seperate rollup for now just so I can try out a bit. Sharing this in case anyone wants to stay in the loop of this.

I think we're going to have to make the Babel switch regardless, so let's not take that as a blocker here.

Yes ofcourse, I'll see if I can help out in that PR.

I made a small POC here, in the jsnext:main field. It's considerably smaller and parses faster. The steps to use it are in the README. It's pretty easy to do a custom redirect in webpack and parcel. Haven't found it for rollup just yet.

Would be cool to start this innovation from here :D

@developit I wonder what you mean with not making it a blocker? Correct me if I'm wrong but the whole reason for babel-preset-env is to enable the behavior we want to push forward here?

@JoviDeCroock Is this closed because there's now an option for modern bundling, or because it's not going to be added?

Because it's there

Sweet, thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

kesla picture kesla  路  4Comments

breadadams picture breadadams  路  3Comments

rzkhosroshahi picture rzkhosroshahi  路  5Comments

sptimer picture sptimer  路  4Comments

dmitrykurmanov picture dmitrykurmanov  路  3Comments