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

Feature request: Add a "module" entry in package.json to export ES2015 version of React #10021

Open
misterfresh opened this issue Jun 21, 2017 · 32 comments

Comments

@misterfresh
Copy link

Do you want to request a feature or report a bug?
Request a feature

What is the current behavior?
React ecosystem was promoting ES6 classes and modules since 2014 and many packages like react-router, redux and so on, have an "es" folder in the npm package with source code in ES2015 modules. Unless I am missing something, it is strange that React itself does not offer that option.

If the current behavior is a bug, please provide the steps to reproduce and if possible a minimal demo of the problem via https://jsfiddle.net or similar (template: https://jsfiddle.net/84v837e9/).
Install react and try to import it in a browser with native modules enabled.

What is the expected behavior?
Have an "es" folder in the npm package with ES2015 modules source code, like most React ecosystem projects do. Allow to import react from ES2015 native modules to make developer workflow more simple.

Which versions of React, and which browser / OS are affected by this issue? Did this work in previous versions of React?
All versions

@Haroenv
Copy link
Contributor

Haroenv commented Jun 23, 2017

The source code of react is still using a custom module system that is close to CommonJS and not using es2015 modules AFAICT. I assume this is why they also aren’t exposed.

@misterfresh
Copy link
Author

misterfresh commented Jun 28, 2017

For anyone bumping into this, it is possible to bundle CommonJS modules as native modules using the config in this file

@lukastaegert
Copy link

At rollup, we were made aware of this issue because you exposed a bug in rollup-plugin-commonjs. in a way, thanks for that 😉. But this would not have happened if react had had a module entry/ES6 export.

Given the recent improvements to rollup's tree-shaking algorithm (and there are more in the pipeline), at least for rollup users, exposing an ES6 bundle might have some positive effects on the bundle size depending on what react features are used. If you want to go there, such a bundle should ideally

  • only provide named exports
  • not create global variables

as this makes it easier for the tree-shaking algorithm to do it's work.

Even though I must admit I do no understand every aspect of react's build script, I would expect this could basically be solved by adding another build target with the correct format + possibly an entry point that has the right exports.

Btw. I noticed you are using a rather old version of rollup. If there is anything preventing you from updating, please file an issue! There is an interesting TODO comment here–is this still current 😜?

@Andarist
Copy link
Contributor

Andarist commented Oct 9, 2017

@lukastaegert are named exports and default ones different in any sense? default is just a named export AFAIK, only treated differently when imported.

@TrySound
Copy link
Contributor

TrySound commented Oct 9, 2017

@Andarist default export can not be changed in runtime. Named exports are bindings, so with let can be changed from file with them.

@lukastaegert
Copy link

lukastaegert commented Oct 9, 2017

Maybe my comment about named exports was a little cryptic, so I will elaborate. I was referring to the not uncommon practice of exporting things twice from a file–once as a named export and once as a member of the default export. The latter is what often prevents tree-shaking for the named export even though the default export is not used. The reason is that in the exporting file, the default export still needs to be assembled and if this assembled object is included in the bundle–which can happen easily for various reasons–all its members will be included in the bundle.

This practice probably stems from the fact that bundlers like webpack and indeed rollup's CommonJS plugin do this themselves when converting CommonJS files. Other libraries that do this include lodash-es. When you remove the default export from node_modules, bundle size after tree-shaking can currently be nearly halved (more would be possible with future improvements).

What does this mean for react? If you make it possible that this

import {Component} from 'react'

can be interchanged with

import React from 'react'
const Component = React.Component

then you always need to assemble the React object which in most likelihood will break most of tree-shaking for the whole package. However I understand that for these decisions, ease of use should always be preferred to premature optimisation. But it is a point to consider especially if you plan to move to a native ES6 modules in the future (which in my opinion you should).

@Andarist
Copy link
Contributor

Andarist commented Oct 9, 2017

Ah, sure - this I understand and I'm aware of. I don't like though recommending only named exports as some kind of the rule of thumb. Way better is to just educate people about consequences of attaching things to the default one (hint hint your eslint plugin ;) )

However I understand that for these decisions, ease of use should always be preferred to premature optimisation. But it is a point to consider especially if you plan to move to a native ES6 modules in the future (which in my opinion you should).

Personally I do not see import {Component} from 'react' any harder to use, assuming it would be exported purely as named export (no attachment to the default one).

Migration to the newer export style could be easily run with a codemod and also a babel plugin could be created to allow people using class MyComponent extends React.Component {} syntax.

@Jessidhia
Copy link
Contributor

@TrySound just a note: a default export is like any other export and can be changed at runtime. It's the export default statement that is the complicated one.

An export default of named function declaration or named class can be reassigned by reassigning to the function/class name, but otherwise it appears non-reassignable. But you can always do a mutable default export by declaring let Identifier and doing export { Identifier as default }.

Not that I recommend doing it as immutability is good for you.

@misterfresh
Copy link
Author

For now I can make it work by manually re exporting the named exports in a separate file, then bundling that file with Rollup.

alt text

@gaearon
Copy link
Collaborator

gaearon commented Oct 11, 2017

I want to make it clear you're not going to get awesome benefits by "tree shaking" React. Most of the code is in the internals that is always used. You might at most shave off one or two kB, and only if your code never uses React.Children.

So this is not a high priority optimization for us for that reason.

@misterfresh
Copy link
Author

For me, the main benefit of having an ES module option for React is to be able to use native modules during development, to avoid rebundling on every change to the code.

@Andarist
Copy link
Contributor

Also with es modules in place webpack could scope hoist react, at the moment it simply bails out on react because it treats it as commonjs.

@gaearon
Copy link
Collaborator

gaearon commented Nov 2, 2017

There's not much you'll gain from scope hoisting React, except for maybe a 1 KB of Children helpers.

@gaearon
Copy link
Collaborator

gaearon commented Nov 9, 2017

For me, the main benefit of having an ES module option for React is to be able to use native modules during development, to avoid rebundling on every change to the code.

Why can't you use the regular UMD build in this case? It would also avoid rebundling.

@gaearon
Copy link
Collaborator

gaearon commented Nov 9, 2017

This is blocked on deciding what we actually want to export from each package, and in which form: #11503
Feel free to comment with proposals there.

Ubehebe added a commit to Ubehebe/react that referenced this issue Oct 24, 2018
`node ./scripts/rollup/build.js ESM_DEV` now produces es module output
for react and react-dom. (ESM_PROD does not work yet, due to
interactions with closure compiler.)

discussion: facebook#10021
@stale
Copy link

stale bot commented Jan 10, 2020

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution.

@stale stale bot added the Resolution: Stale Automatically closed due to inactivity label Jan 10, 2020
@TrySound
Copy link
Contributor

TrySound commented Jan 10, 2020

not stale

@stale stale bot removed the Resolution: Stale Automatically closed due to inactivity label Jan 10, 2020
@stale
Copy link

stale bot commented Apr 9, 2020

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

@stale stale bot added the Resolution: Stale Automatically closed due to inactivity label Apr 9, 2020
@just-boris
Copy link
Contributor

If this issue is still affecting you, please leave any comment

any comment

@stale stale bot removed the Resolution: Stale Automatically closed due to inactivity label Apr 9, 2020
@luxp
Copy link

luxp commented Jun 11, 2020

Really want ESModule export, cause there is some cool things like vite, snowpack, etc need the esmodule support.

@stale
Copy link

stale bot commented Sep 11, 2020

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

@stale stale bot added the Resolution: Stale Automatically closed due to inactivity label Sep 11, 2020
@dominic-p
Copy link

any comment

@stale stale bot removed the Resolution: Stale Automatically closed due to inactivity label Sep 11, 2020
@stale
Copy link

stale bot commented Dec 25, 2020

This issue has been automatically marked as stale. If this issue is still affecting you, please leave any comment (for example, "bump"), and we'll keep it open. We are sorry that we haven't been able to prioritize it yet. If you have any new additional information, please include it with your comment!

@stale stale bot added the Resolution: Stale Automatically closed due to inactivity label Dec 25, 2020
@petersolopov
Copy link

any comment

@stale stale bot removed the Resolution: Stale Automatically closed due to inactivity label Dec 25, 2020
@beginor
Copy link

beginor commented Feb 8, 2021

Waiting for ESModule export of react!

@iMakedonsky
Copy link

One more to that, waiting es modules

@anumthapa

This comment has been minimized.

@samwightt
Copy link

Really could use this being a thing. CDNs like JSDelivr's new ESM CDN are really cool, but they're not able to load React. As far as I know the only ESM CDN I know of that's able to work properly with React is the Skypack. Every other view library I know of works properly across the major CDN providers except for React :(

@jollytoad
Copy link

I've been experimenting recently with import-maps aided by the JSPM CDN and import-map generator, and am surprised and disappointed to find that react doesn't have a pure ESM build in its package (just cjs and umd). This is not about tree-shaking, bundling, or optimisation ... it's about choice, the choice to progress the state of JS in the browser, the choice to experiment with and embrace these new technologies such as import-maps, that have the very real potential to bring an end to the bundling madness.
Please, please, please, add a simple ESM build, along with appropriate 'module' & 'exports' fields into the package.json.

@steve-taylor
Copy link

Hybrid (CommonJS and ESM) packages are too much hassle, e.g. dual package hazard which can easily break React, Styled Components, etc.

It's time to let CommonJS die and go all in on ESM. A number of packages have gone pure ESM and if React did too, it would be a huge signal to the ecosystem that CommonJS is on its last legs.

@kungfooman
Copy link

@steve-taylor Totally agree, but it's now 2023 and the issue has been open since 2017. I think we have to wait a few more years?

@GabrielDelepine
Copy link

the issue has been open since 2017

Sorry but this is not a constructive comment. We all know for how long this issue is opened, it is not even an argument.
Please be patient or fix the issue by opening a PR

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