From fe00f143c6abd2e7d2e23bae7a493ede7505627d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C2=ABSergei?= Date: Wed, 13 May 2026 13:20:51 +0300 Subject: [PATCH] Preserve JSX pragmas before compiler imports --- .../src/Entrypoint/Imports.ts | 34 +++++++++++++++++++ .../src/__tests__/Imports-test.ts | 30 ++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 compiler/packages/babel-plugin-react-compiler/src/__tests__/Imports-test.ts diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts index 15796d77a70e..ad4f18013763 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Imports.ts @@ -302,9 +302,43 @@ export function addImportsToProgram( } } } + preserveLeadingJsxPragmaCommentsOnInsertedStatements(path.node, stmts); path.unshiftContainer('body', stmts); } +function preserveLeadingJsxPragmaCommentsOnInsertedStatements( + program: t.Program, + stmts: Array, +): void { + const firstInsertedStmt = stmts[0]; + const firstExistingStmt = program.body[0]; + if ( + firstInsertedStmt == null || + firstExistingStmt == null || + firstExistingStmt.leadingComments == null + ) { + return; + } + const remainingComments = []; + const jsxPragmaComments = []; + for (const comment of firstExistingStmt.leadingComments) { + if (/@jsx(?:ImportSource|Runtime|Frag)?\b/.test(comment.value)) { + jsxPragmaComments.push(comment); + } else { + remainingComments.push(comment); + } + } + if (jsxPragmaComments.length === 0) { + return; + } + firstInsertedStmt.leadingComments = [ + ...(firstInsertedStmt.leadingComments ?? []), + ...jsxPragmaComments, + ]; + firstExistingStmt.leadingComments = + remainingComments.length === 0 ? null : remainingComments; +} + /* * Matches `import { ... } from ;` * but not `import * as React from ;` diff --git a/compiler/packages/babel-plugin-react-compiler/src/__tests__/Imports-test.ts b/compiler/packages/babel-plugin-react-compiler/src/__tests__/Imports-test.ts new file mode 100644 index 000000000000..f3ef8ce602cf --- /dev/null +++ b/compiler/packages/babel-plugin-react-compiler/src/__tests__/Imports-test.ts @@ -0,0 +1,30 @@ +/** + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import invariant from 'invariant'; +import {runBabelPluginReactCompiler} from '../Babel/RunReactCompilerBabelPlugin'; + +it('preserves JSX pragmas before generated runtime imports', () => { + const result = runBabelPluginReactCompiler( + `/* @jsxImportSource custom-jsx */ + +import {useState} from 'react'; + +export default function Component({children}) { + const [count] = useState(0); + return
{children}
; +}`, + 'test.tsx', + 'typescript', + {panicThreshold: 'all_errors'}, + ); + + invariant(result.code != null, 'Expected Babel transform to emit code'); + expect(result.code.indexOf('@jsxImportSource custom-jsx')).toBeLessThan( + result.code.indexOf('react/compiler-runtime'), + ); +});