-
Notifications
You must be signed in to change notification settings - Fork 143
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
Add support for new React 17 JSX transform #585
Comments
This would be awesome! I would definitely use it in vite-react-jsx, as using Babel makes build times ~40% longer for the |
I'm finally getting around to this one. As mentioned, there are lots of open questions and details, so I wrote up a tech plan to help gather my thoughts https://github.com/alangpierce/sucrase/wiki/JSX-Automatic-Runtime-Transform-Technical-Plan Here's a quick summary:
|
Progress toward #585 This change extends the parser to detect two JSX cases that are needed for the automatic runtime. The new code is run unconditionally, even in the old transform, since flagging it would have its own overhead and complexity. The new JSX transform needs to distinguish children being static or non-static, where static is equivalent to having at least two comma-separated children emitted by the old transform or any child being a spread child. The main challenge in getting this right is that JSX whitespace-trimming will sometimes completely remove all content from a text range, in which case it shouldn't count as a child for the purposes of counting the number of children. Fortunately, there is a relatively simple algorithm to detect if a text range is empty: it's empty if and only if it is entirely whitespace and has at least one newline. To identify these "empty text" regions, I added a new token type `jsxEmptyText` that is treated the same except for the purposes of counting children. In the future, it likely is reasonable to not treat such a region as a token in the first place. The new JSX transform also needs to detect the pattern of a key appearing after a prop spread. We don't do keyword detection on JSX prop names, so instead I manually detect the name "key", but only if we have already seen a prop spread.
Progress toward #585 This change extends the parser to detect two JSX cases that are needed for the automatic runtime. The new code is run unconditionally, even in the old transform, since flagging it would have its own overhead and complexity. The new JSX transform needs to distinguish children being static or non-static, where static is equivalent to having at least two comma-separated children emitted by the old transform or any child being a spread child. The main challenge in getting this right is that JSX whitespace-trimming will sometimes completely remove all content from a text range, in which case it shouldn't count as a child for the purposes of counting the number of children. Fortunately, there is a relatively simple algorithm to detect if a text range is empty: it's empty if and only if it is entirely whitespace and has at least one newline. To identify these "empty text" regions, I added a new token type `jsxEmptyText` that is treated the same except for the purposes of counting children. In the future, it likely is reasonable to not treat such a region as a token in the first place. The new JSX transform also needs to detect the pattern of a key appearing after a prop spread. We don't do keyword detection on JSX prop names, so instead I manually detect the name "key", but only if we have already seen a prop spread.
Fixes #585 Tech plan: https://github.com/alangpierce/sucrase/wiki/JSX-Automatic-Runtime-Transform-Technical-Plan This PR adds two new options: * `jsxRuntime`, which can be "classic" (the existing behavior) or "automatic" (the transform behavior released with React 17). * `jsxImportSource`, which configures the import prefix when using the automatic runtime. This PR also makes these options available for the website.
Follow-up to #585 This PR also resolves pre-existing key issues. I also tried a separate prod build to confirm that `production: true` is necessary to avoid a runtime error.
Follow-up to #585 This PR also resolves pre-existing key issues. I also tried a separate prod build to confirm that `production: true` is necessary to avoid a runtime error.
React has a published a description of a new JSX transform with a corresponding runtime library available in new React versions: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html . TypeScript (and others) have already implemented the new transform: https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#jsx-factories . Sucrase should implement some support for it, though the details are still an open question.
Unfortunately, it looks like it's unlikely to simplify the JSX transform for Sucrase, and will likely make it harder. For example:
jsx
orjsxs
based on whether the children section (later on in the code) has at least two elements explicitly specified. This sort of "lookahead" behavior isn't well-supported by Sucrase, but could probably be implemented via a special case in the parser and a new token type or a new flag on the token object.key
prop and reorder it to come after the props. Since the key could be an arbitrary expression that may contain newlines, it will be a challenge to correctly preserve line numbers like the rest of Sucrase does. If we simply move the key expression to after the props (preserving newline chars in each), then we'll end up with broken breakpoints if you try to debug within a callback prop. This issue also affected the class fields implementation before I rewrote it in Change class field implementation to use initializer methods #313 to keep the code in order. There might be a clever alternative transform that preserves order, like using a comma expression to assign to an intermediate variable, but it certainly seems like a pain.jsxDEV
function that will fail if used in production (from my reading). That will likely make Sucrase's zero-configuration goal harder; if we use dev mode by default, it will completely break in production, and if we use prod mode by default, it will miss useful debugging info in dev.There are some positives with the new system, though:
importSource
) rather than two.React
andcreateElement
) so they can be separately handled to account for import renaming.The text was updated successfully, but these errors were encountered: