-
Notifications
You must be signed in to change notification settings - Fork 47.1k
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
Transpile JSX to namespace import in automatic runtime #20113
Comments
Hi! It is intentional that the Babel transform compiles to the named import. While I get the short-term motivation, in the longer run named imports are better because they are less powerful, which leaves different tools in the middle more opportunities to optimize. E.g. a bundler or a minifier can reason about the function alone, without worrying about the intermediate object (and whether it needs to be created, and then safely eliminated). It is harder to guarantee that the function name can be safely minified if we're using a namespace import. Indeed, Webpack 4 output is suboptimal but we can live with it because this version won't be popular forever and the community will move on. Webpack 5 output seems mostly reasonable. (It's still not ideal but have there been any perf benchmarks demonstrating significant negative runtime impact?) In the longer run we'll ship React as ESM and the problem will go away. Let's not compromise on the long term in favor of short term. If someone would like to fix this in short term, it would be doable with a Babel plugin at the end of the chain — but let's keep the upstream clean. |
Thanks, I appreciate the thoughts and context.
Yeah, the idea of not wanting to trade off on the long term makes sense. I'd viewed it as neutral in the long term because Rollup and Webpack 4/5 are quite aggressive about not materializing namespace imports from ESM modules into objects when inlining, so there's generally no property access passed to minifiers. But I see why you'd want to be extra cautious about this and/or allow for a wider range of bundlers, etc.
That's a great point, thanks. I'll add this to our preset. 🙂 |
As mentioned in the blog post, the current automatic JSX runtime transform transpiles the following code:
To roughly:
Unfortunately, the bundling story for this kind of import from a CJS module like
'react/jsx-runtime'
isn't great, because Webpack needs to be conservative about inter-op. Webpack 4 ends up bundling it as something like this:Webpack 5 does slightly better:
But these are both pretty unfortunate. The
jsx
family of functions never usesthis
so the context escape is unnecessary, but Webpack doesn't know that. This was raised on Twitter here.However, this can actually be fixed by having the JSX transform create a namespace import instead of a named one. In other words, if it instead transpiled the above code to:
Webpack 4 and 5 will both bundle that code to something like:
Which is the desired output. It's smaller and more efficient than either of the alternatives.
(The only improvement from there would be to call
jsx
directly, but that isn't possible until the runtime is available as an ESM module and Webpack can inline and concatenate it. I won't get into that here, although it would be really nice. 🙂)I know that this change would get made in the Babel repo rather than here, but I wanted to run it by the React team first. @gaearon and @lunaruan, do you see any reason not to make this change?
The text was updated successfully, but these errors were encountered: