Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: option for modern bundling. #304

Closed
JoviDeCroock opened this issue Jan 20, 2019 · 19 comments
Closed

RFC: option for modern bundling. #304

JoviDeCroock opened this issue Jan 20, 2019 · 19 comments

Comments

@JoviDeCroock
Copy link
Contributor

JoviDeCroock commented Jan 20, 2019

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

@ForsakenHarmony
Copy link
Collaborator

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

@JoviDeCroock
Copy link
Contributor Author

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

@Andarist
Copy link
Collaborator

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.

@JoviDeCroock
Copy link
Contributor Author

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.

@developit
Copy link
Owner

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?

@JoviDeCroock
Copy link
Contributor Author

JoviDeCroock commented Jan 30, 2019

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.

@JoviDeCroock
Copy link
Contributor Author

JoviDeCroock commented Feb 5, 2019

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.

@developit
Copy link
Owner

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.

@JoviDeCroock
Copy link
Contributor Author

JoviDeCroock commented Feb 22, 2019

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

@developit
Copy link
Owner

developit commented Feb 23, 2019

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.

@JoviDeCroock
Copy link
Contributor Author

JoviDeCroock commented Feb 24, 2019

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.

@developit
Copy link
Owner

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

@JoviDeCroock
Copy link
Contributor Author

JoviDeCroock commented Feb 25, 2019

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

@JoviDeCroock
Copy link
Contributor Author

@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?

@rmacklin
Copy link

rmacklin commented Jan 8, 2020

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

@JoviDeCroock
Copy link
Contributor Author

Because it's there

@rmacklin
Copy link

rmacklin commented Jan 8, 2020

Sweet, thanks!

@VikasAgarwal1984
Copy link

From the documentation, it seems target and module will be ignored in tsconfig:
https://github.com/developit/microbundle

For following command:
microbundle --tsconfig tsconfig.json --css external --target web --jsx React.createElement -f esm,modern

with tsconfig, target set to esnext or es2020
microbundle -f esm always transpile down to es6.

.browserlistrc is configured to use
last 1 chrome versions

npx browserslist
chrome 98

i thought esm will transpile it to es2017, is there an understanding gap here?

@rschristian
Copy link
Collaborator

From the documentation, it seems target and module will be ignored in tsconfig:

Yes, whatever you use for "target" and "module" in your tsconfig.json will be ignored/overwritten. They're not really relevant past using plain tsc anyways.

i thought esm will transpile it to es2017

No, that's modern.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants