Skip to content

Port JSX Emit #1159

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

Merged
merged 11 commits into from
Jun 11, 2025
Merged

Port JSX Emit #1159

merged 11 commits into from
Jun 11, 2025

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Jun 11, 2025

I'm still going through the baseline diffs and trying to minimize the bad ones, but there are two notable things I've seen already:

  • printer.EFStartOnNextLine is not yet implemented, so all tag emit occurs on one line (this is also used lightly by the cjs module transform)

@Copilot Copilot AI review requested due to automatic review settings June 11, 2025 00:45
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR, titled "Port JSX Emit", addresses two main issues: ensuring that files containing JSX tags are correctly marked as modules to allow proper JSX emit, and implementing printer.EFStartOnNextLine so that tag emit occurs on separate lines. Key changes include updating baseline outputs for JSX expressions to use React.createElement, refactoring JSX intrinsic name checks to use the new scanner.IsIntrinsicJsxName function, and incorporating JSX transformers into the emitter workflow.

Reviewed Changes

Copilot reviewed 429 out of 429 changed files in this pull request and generated no comments.

Show a summary per file
File Description
testdata/baselines/reference/submodule/compiler/commentsOnJSXExpressionsArePreserved(jsx=react,module=commonjs,moduledetection=legacy).* Updated conversion of JSX literals to React.createElement calls for legacy module detection
testdata/baselines/reference/submodule/compiler/commentsOnJSXExpressionsArePreserved(jsx=react,module=commonjs,moduledetection=force).* Similar JSX output changes for force module detection
testdata/baselines/reference/submodule/compiler/commentsOnJSXExpressionsArePreserved(jsx=react,module=commonjs,moduledetection=auto).* Alignment of JSX baseline outputs for auto module detection
testdata/baselines/reference/submodule/compiler/callsOnComplexSignatures.* Adjusted component rendering syntax with new element creation patterns and const declarations
internal/transformers/, internal/printer/, internal/checker/, internal/scanner/, internal/ast/* Refactored helper methods, updated intrinsic JSX name checks, and added new functionality for JSX emit and assign helpers
Comments suppressed due to low confidence (2)

internal/checker/grammarchecks.go:1198

  • Verify that scanner.IsIntrinsicJsxName fully replicates the previous behavior of IsIntrinsicJsxName to prevent any regression in handling JSX names for namespaced nodes.
if ast.IsJsxNamespacedName(node) && c.compilerOptions.GetJSXTransformEnabled() && !scanner.IsIntrinsicJsxName(node.AsJsxNamespacedName().Namespace.Text()) {

internal/checker/utilities.go:1336

  • Ensure that transitioning to scanner.IsIntrinsicJsxName from the previous version does not introduce subtle differences in JSX tag name validation.
return ast.IsIdentifier(tagName) && scanner.IsIntrinsicJsxName(tagName.Text()) || ast.IsJsxNamespacedName(tagName)

@jakebailey
Copy link
Member

  • SourceFile.ExternalModuleIndicator isn't set on files containing JSX tags, so if this is the only indicator a file is a module, implicit jsx runtime imports do not emit correctly in that file in jsx emit modes which use them (I think this is being worked on already?)

This should now be there in main as of earlier today, so that should just work if you merge.

@weswigham
Copy link
Member Author

This should now be there in main as of earlier today, so that should just work if you merge.

Yes, but on investigation, a weeee bit off. One of those true early returns shoulda been a false - as-is, finding a subtree with no JSX stops it from looking for JSX in any other nodes, which, in turn, prevents finding a JSX tag pretty reliably. I've pushed the fix and updated baselines here.

@jakebailey
Copy link
Member

Great, thanks! 😄

Copy link
Member

@jakebailey jakebailey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the diffs fall into a couple of buckets.

(Most are ES5, or AMD/System/etc, which I am working to remove from our submodule)

@@ -38,21 +38,19 @@
// Pair of non-like intrinsics
function render(url) {
- var Tag = url ? 'a' : 'button';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm working on dropping ES5 out of the submodule, so theoretically that'd eliminate a load of diffs here too.

+
+
+ </div>;
+ return jsx_runtime_1.jsx("div", { children: null /* preserved */ });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One difference I'm seeing is that the (0, ...) is missing. I'm not 100% sure who's in charge of adding that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea tbh - not the JSX transform, tho, that's for sure. I think it's a downleveling one, though.

+
+
+ </div>;
+ return _jsx("div", { children: null /* preserved */ });
}
- Component.prototype.render = function () {
- return (0, _a.jsx)("div", { children: null /* preserved */ });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seemingly missing whatever _a was?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the emit when the file's module transform isn't the same as in Strada, as the substitution from _jsx to mod.jsx is done by the cjs transform. It implies something is still off with the module detection logic or substitution compared to strada - in this case, when moduleDetection: legacy is set. In this case, though, I don't think it's an important diff - the behavior of jsx auto-imports in script files (which this is) is explicitly not actually stable.

@weswigham
Copy link
Member Author

Seems like the diffs fall into a couple of buckets.

Yeah, the vast majority remaining are const instead of var (or less so, other downleveling) and the multiline emit.

@weswigham weswigham requested a review from jakebailey June 11, 2025 20:48
@tmm1
Copy link
Contributor

tmm1 commented Jun 11, 2025

Happy to see someone working on the emit side! 🙏🏽

@weswigham weswigham added this pull request to the merge queue Jun 11, 2025
Merged via the queue into microsoft:main with commit e475191 Jun 11, 2025
22 checks passed
@weswigham weswigham deleted the jsxemit branch June 11, 2025 22:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants