-
Notifications
You must be signed in to change notification settings - Fork 46.9k
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
Formalize top-level ES exports #11503
Comments
Imho export const Component = ...
export default React
React.Component = Component |
Is there a technical reason why? (Aside from having two ways to do the same thing.) My impression is that people who would import |
That questions can be probably best answered by @lukastaegert. Ain't sure if something has changed since #10021 (comment) Also Rollup is not the only tree shaker out there, and while webpack's tree-shaking algorithm is worse than the one in rollup, it's usage is probably way higher than rollup's (both tools do excellent jobs ofc, I don't want to offend anyone, just stating facts) and if we can (as the community) help both tools at once we should do so whenever we can. |
is tree-shaking going to do anything in React's case, given that everything is preprocessed into a single flat bundle? I wonder what the primary import style is for React, personally i tend to treat it like a default export e.g. |
As @gaearon already stated elsewhere, size improvements in case of react are expected to be minimal. Nevertheless, there ARE advantages:
As for the kind of exports, of course only named export really provide the benefit of easy tree-shaking (unless you use GCC which might be able to do a little more in its aggressive move and maybe the latest rollup if you are really lucky). The question if you provide a default export as well is more difficult to decide:
As a two-version migration strategy, you might add a default export in the next version for compatibility purposes which is declared deprecated (it might even display a warning via a getter etc.) and then remove it in a later version. |
This is also an interesting case: #11526. While monkeypatching for testing is a bit shady, we'll want to be conscious about breaking this (or having a workaround for it). |
Came here via this Twitter conversation. For me, there's a clear correct answer to this question: React and ReactDOM should only export named exports. They're not objects that contain state, or that other libraries can mutate or attach properties to (#11526 notwithstanding) — the only reason they exist is as a place to 'put' (It also makes life easier for bundlers, but that's neither here nor there.) Of course, that does present a breaking change for people currently using a default import and transpiling. @lukastaegert probably has the right idea here, using accessors to print deprecation warnings. These could be removed in version 17, perhaps? I don't have a ready-made suggestion for #11526 though. Perhaps shipping ESM would have wait for v17 for that reason anyway, in which case there'd be no need to worry about deprecation warnings. |
People have really come to like import React, { Component } from 'react' so convincing them to give it up might be difficult. I guess this is not too bad, even if a bit odd: import * as React from 'react';
import { Component } from 'react'; To clarify, we need import {jsx, Component} from 'react'; which is maybe okay but a huge change. This would also mean React UMD builds now need to set Why am I suggesting import * as React from 'react';
import { Component } from 'react'; and keep JSX transpiling to |
Confession: I always found it slightly odd that you have to explicitly import import { Component } from 'react'; ...and the namespace import would be taken care of automatically. |
In a distant future, maybe. For now we need to make sure transpilers work with other module systems (CommonJS or globals). Making this configurable is also a hurdle, and further splits the community. |
What @Rich-Harris suggested (inserting a specific import when jsx is used) is easily done by transpilers plugin. The community would have to upgrade their Of course we need to consider other module systems, but it doesn't seem like a hard problem to solve. Are there any specific gotchas in mind? |
I don’t know, what is your specific suggestion as to how to handle it? Would what the default be for Babel JSX plugin? |
What people? Come forth so that I may mock thee. |
I did that a lot 🙂 Pretty sure I've seen this in other places too. |
Default is at the moment I think as es modules are basically the standard way (although not yet adopted by all) of doing modules, it is reasonable to assume majority is (or should) use it. Vast majority already uses various build step tools to create their bundles - which is even more true in this discussion because we are talking about transpiling jsx syntax. Changing the default behaviour of the jsx plugin to auto insertion of Having this configurable to bail out to today's behaviour (assuming present in scope) seems really like a minor change in configuration needed for a minority of users and an improvement (sure, not a big one - but still) for majority. |
Thanks to @alexlamsl $ cat mod.js
export default {
foo: 1,
bar: 2,
square: (x) => x * x,
cube: (x) => x * x * x,
}; $ cat main.js
import mod from './mod.js'
console.log(mod.foo, mod.cube(mod.bar)); $ rollup main.js -f es --silent | tee bundle.js
var mod = {
foo: 1,
bar: 2,
square: (x) => x * x,
cube: (x) => x * x * x,
};
console.log(mod.foo, mod.cube(mod.bar));
$ cat bundle.js | uglifyjs --toplevel -bc
var mod_foo = 1, mod_bar = 2, mod_cube = x => x * x * x;
console.log(mod_foo, mod_cube(mod_bar)); $ cat bundle.js | uglifyjs --toplevel -mc passes=3
console.log(1,8); |
wow, that's great new 👏 is Anyway - that's all and nice in a rollup world, but considering that |
As stable as anything else in the JS ecosystem. Over 500K downloads per week.
Anyway, it's an option. Webpack defaults are not ideal anyway - you have to use |
Adding a few cents here:
So if we are at a point where we might make breaking-change decisions, I would advise to change this so that JSX depends on a single (global or imported) function. I would have called it This would also at last decouple JSX from React in a way such that other libraries can choose to support JSX by using the same transformation and supplying a different |
Personally I do not see much gain in migrating to |
This is probably slightly tangential to the main discussion, but I'm curious how well ES modules work with checking react/packages/react/npm/index.js Lines 3 to 7 in d9c1dbd
I may be missing something obvious here, but I'm struggling to see how to translate this pattern into ES modules? |
@NMinhNguyen Conditional exports aren't possible with ES modules. |
|
@Andarist @milesj Thanks for confirming my suspicion :)
From the React 16 blog post I thought that the
Like, I'm not sure how one could use the |
This for sure is a drawback, because there is no standard way at the moment for doing this. OTOH it's just a matter of tooling, it is possible (and it's rather easy) to compile this in build steps of your application even today. Ofc it would be easier if package could expose dev/prod builds and the resolver would just know which one to pick, but maybe that's just a matter of pushing this idea to tooling authors. |
I assure you, it is not a question of "defaults". It is not impossible, but at least for Rollup, there is still some engineering effort necessary to safely track usage of object properties as would be required for CommonJS tree-shaking. And beyond tree-shaking, scope-hoisting is another optimization you forego without ES modules. In short it means you have a lot more property accesses with the incurred runtime penalty in a CommonJS setting. Rollup is actively trying to reduce these, but it requires libraries to be sufficiently "well-behaved". In short, it is quite hard to produce similar quality output from CommonJS modules as opposed to ES modules. |
Since dynamic imports exist, well-behaved libraries are required anyways. |
The plan for React 18 is finally announced, but I'm a little disappointed that there is no mention of ES module support at all. |
One of our main goals for the 18.0 release is to remove as many upgrade obstacles as possible so that people can migrate and began taking advantage of the new features and fixes. ES modules would be a breaking change (so they would compete with this goal). They are still important to us though, and we hope to make the change sometime in the near future, just not as part of 18.0. |
There is currently much confusion about whether to I'd really appreciate an official stance by the React developers as to which form will be supported once React starts providing native ESM, so that we can start educating people now, update examples, blog posts, provide linter rules, emit bundler warnings etc now, rather than wait with it until the ESM support finally ships… |
Pretty sure the path forward is named imports only, so At work, we completely removed the default import and used the new transformer without any issues. It's much much cleaner. |
I'm a little bit confused about the roadmap now. If ES module will not come with v18.0, will it come with v18.x or v19.0? (or ... even later?) I'm not sure if React.js follows semantic versioning. If it does, it's actually OK to introduce a breaking change in a major release. If React.js doesn't follow semantic versioning and finally supports ES module in v18.x, it's still weird that React.js does not introduce breaking changes in a major version but introduces them in a minor version. If React.js finally supports ES module in v19.0, OK, maybe we have to wait another 4 years for the ES module support. |
may I know if we have any status for the ESM module support from React? |
If #18102 is to be believed, then the react team has decided on ESM exports… namely on using named exports instead of a default export. So… can this be closed? |
ES modules have been supported in major browsers for over 5 years now. When would an official ESM version of React be finally published? |
If the transition to ESM is not made properly, it will be a terrible mess. I am like you, I can't wait but I definitely prefer the team to take enough time to ship something great. Don't underestimate the amount of work, it's huge because they are so many implications Until then, I am loading package.json
tsconfig.json (Typescript 5.0)
index.html
|
Please support ESM as soon as possible, it is useful, thanks. It is currently available for temporary use https://esm.sh/ To get the ESM package for React. |
I second the suggestion to use No need for bundlers or arcane legacy module stuff. Bundling is for optimisation and for legacy browser support and should provide compatibility with ESM and not fight against it. IMHO, a bundler should no longer be a development time dependency in 2023. Just do:
|
@gaearon Now that the new JSX transform has been out for a while, there should no longer be a blocker right? Perhaps the time is right to do this with React 19. How would you feel if I drafted up a renewed proposal along the lines of reactjs/rfcs#38? |
Guys please, is there any update on this? |
While it's not as much of a problem in smaller applications, larger application with hundreds/thousands of sources files will always have a need for a build step as shipping sources directly cannot be as efficient as a tool designed to organize sources into an optimized output. "Bundlers" are reasonable as they can take advantage of compression, dead code elimination, and consuming invalid browser sources (like JSX syntax, TypeScript, importing css into JS, importing images, markdown, plaintext, json, etc). You could argue that you could just use a minifier and strip types on your sources before publishing.... but then you're basically making a bundler. For the most part in 2024, it's practical to think of JavaScript as simply a pseudo "binary" format for the web that compilers target.
I'm advocating for React being distributed in spec-compliant ESM that can be run directly in the browser - with or without a bundler. As a bundler developer, I wish wholeheartedly that all web applications/libraries would be written in spec-compliant ESM but it's just not like that in the real world. Even packages distributed today as ESM packages often still use Nodejs's CJS resolution algorithm, omit extensions from imports, etc. So not even ESM packages are really valid ESM - it's a nightmare. React, CJS and Optimising OutputsReact being distributed as CJS forces bundlers to de-optimize everything relating to React. It cannot be tree-shaken and forces bundlers to ship CJS emulation/polyfills to the browser when React is present. One example of a deoptimization is; because CJS exports can be modified at runtime, bundlers cannot assume stable exports for CJS values. For example, look at this abomination: const foo = require('./something')
setTimeout(() => {
foo.bar = 'I reassigned a value in another module at runtime'
}, 2000) Why is this legal?!?! 😆 So bundler CJS emulation involves checking the value of every In the case of React, how many times do you call For the love of all things good, please distribute React as unminified, browser compliant, ESM |
Currently we only ship CommonJS versions of all packages. However we might want to ship them as ESM in the future (#10021).
We can't quite easily do this because we haven't really decided on what top-level ES exports would look like from each package. For example, does
react
have a bunch of named exports, but also a default export calledReact
? Should we encourage people toimport *
for better tree shaking? What aboutreact-test-renderer/shallow
that currently exports a class (and thus would start failing in Node were it converted to be a default export)?The text was updated successfully, but these errors were encountered: