-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
jsx set to "preserve" still applies transforms to JSX #3605
Comments
I created the same jsx transform in tsc compiler with jsx preserve. tsc does seem to be significant whitespace aware. They probably take the approach of outputting the raw value from the AST for JSXText nodes. Is there an opportunity to skip iterative JSX generation entirely for preserve mode and somehow splice in the jsx segments into the output from the AST locations? |
The reason this is happening is because esbuild is parsing JSX into an AST and then printing it back out. In other words, the ASTs that esbuild makes for both the input and the output are exactly the same, just printed differently. You can see here that both the input and the output are equivalent when transformed into JS: (link) You haven't described an actual problem you are having. Why is this a problem for you? |
Sure thing! I am applying an ahead-of-time compile transformation to JSX directly after the esbuild step in vite.It works great to have esbuild handle the typescript to jsx conversion, then I use acorn+jsx parser to get the ast and handle the custom generation, hmr, etc. Its a fast compilation pipeline. The difference in jsx output messes with the subsequent html generation and binding targets. It ends up reversing the optimizations of moving html content out of js files and multiplies the number of binding targets generated. This jsx: const render = () => <li className={category}>Hello {place}</li>; Generates this html/js: <li data-bind>Hello <!--0--></li> const render = () => {
const { node: te19fd83eae, targets: __targets } = __rendererById('e19fd83eae');
const __target0 = __targets[0];
const __child1 = __target0.childNodes[1];
__target0.className = (category);
__compose(place, __child1);
return te19fd83eae;
}; While this jsx: const render = () => <li className={category}>
{"Hello "}
{place}
</li>; generates this html/js: <li data-bind="">
<!--0-->
<!--0-->
</li> const render = () => {
const { node: t43944ca1c9, targets: __targets } = __rendererById('43944ca1c9');
const __target0 = __targets[0];
const __child1 = __target0.childNodes[1];
const __child2 = __target0.childNodes[3];
__target0.className = (category);
__compose("Hello ", __child1);
__compose(place, __child2);
return t43944ca1c9;
}; |
I see. My intuition as a developer is that those two cases would be equivalent since I'd expect any relevant optimizations to be applied regardless of how the source code was written (e.g. But I can still see an argument for changing esbuild's behavior here. The intent behind the word "preserve" is "doesn't change" and if someone wants to make One random caveat with this is that the |
Intuition shaped by vdom architecture. 😁 For a render-once architecture you want to offload as much into the static initial html because then it is processed by the browser and not the library/fw. I was really impressed with how well esbuild does static optimization and inlining. It was hard to make a test case to "fool" it into outputting variables instead of static text. Even module boundaries are no obstacle! I am going to look at using that capability to try and "bundle" trees of components into equivalent single components. |
Working reproduction
Esbuild with these inputs:
jsx: 'preserve, loader: 'tsx'
Expected output is that jsx is "preserved" as-is:
Actual output transforms JSXText to JSXExpressionContainer (and removes JSXExpressionContainer from literal attirbute. Also introducing additional formatring which has downstream effect of introducing additional text nodes:
(LMK if I am just missing another setting!)
AFAICT, here is where the transform is applied.
IMO
jsx: 'preserve'
should not make any JSX transforms that would result in a different JSX AST being produced from the output what was produced for the jsx from the source.Happy to help with test/PR if needed.
The text was updated successfully, but these errors were encountered: