Add emit support for jsx/jsxs experimental jsx runtime api by weswigham · Pull Request #39199 · microsoft/TypeScript
This adds two new options for the jsx compiler option - react-jsx, and react-jsxdev. They use the jsx and jsxDEV constructors and the react/jsx-runtime and react/jsx-dev-runtime entrypoints, respectively. The primary differences, as noted in the linked issue, are that children are passed as part of the props object, and the key is passed as a separate argument. (The jsxDEV constructor further takes some debug data.) In addition, this adds a jsxImportSource compiler option (and @jsxImportSource file pragma) to control the root specifier the jsx runtime is imported from (which defaults to react). In it's current state, I believe this is usable, but there are some known flaws:
- The checker/program need to load the
jsxImportSourcemodule and use it as the source for the JSX namespace automatically. Presently you need to include it in the program yourself (ie, with atypesdirective or compiler option). This is moreso a TODO for myself, since I don't think there's any question to what we should do (implicitly include the package or@typesversion in the program). This is more interesting for thejsxImportSourcepragma, which, for all intents and purposes, is animportstatement. We have a lot of services for real import statements - should they be applied to the pragma, where possible? - Babel additionally supports a
jsxRuntimepragma (with valuesclassicorautomatic) to swap between the old emit and the new one. This is supportable; however currently I only key our emit off thejsxcompiler option, and the presence of thejsxImportSourcepragma. - In some cases, the new transform still falls back to
createElement(when akeyprop follows a spread) - this is a kind of soft deprecation; however it still implicitly imports the jsx runtime and pulls increateElement. This PR does not yet do this, as, awkwardly enough, the modulecreateElementis supposed to come from is different from thejsx-runtimemodule entrypoint. I could make this work, but I think this is something we should provide some feedback on - so long as there's still acreateElementfallback required in the API, why can't it be exported by the same entrypoint exportingjsxorjsxDEV? - Without an import or export, a file is not marked as a module, and will not have an import automatically added. Should this issue an error? Or should, under these
jsxmodes, the presence of a jsx tag imply module-ness?
Fixes #34547
This is currently experimental in babel, and AFAIK not yet supported in a stable version of react; as such, we should probably continue to experiment with it for awhile before merging it into a stable release.
TL;DR
When jsx: react-jsx (and target: esnext) is set,
export default (props: {className: string}) => <div className={props.className} key="stablekey">childtext</div>
compiles to
import { jsx as _jsx } from "react/jsx-runtime"; export default (props) => _jsx("div", Object.assign({ className: props.className }, { children: "childtext" }), "stablekey");