Repository: facebook/react
Pull request: [compiler] Allow ReactElement symbol to be configured when inlining jsx

Based on https://github.com/facebook/react/pull/30995 ([rendered diff](https://github.com/jackpope/react/compare/inline-jsx-2...jackpope:react:inline-jsx-3?expand=1))

____

Some apps still use `react.element` symbols. Not only do we want to test there but we also want to be able to upgrade those sites to `react.transitional.element` without blocking on the compiler (we can change the symbol feature flag and compiler config at the same time).

The compiler runtime uses `react.transitional.element`, so the snap fixture will fail if we change the default here. However I confirmed that commenting out the fixture entrypoint and running snap with `react.element` will update the fixture symbols as expected.


Changed files:
filename: compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
patch: @@ -352,8 +352,8 @@ function* runWithEnvironment(
     });
   }
 
-  if (env.config.enableInlineJsxTransform) {
-    inlineJsxTransform(hir);
+  if (env.config.inlineJsxTransform) {
+    inlineJsxTransform(hir, env.config.inlineJsxTransform);
     yield log({
       kind: 'hir',
       name: 'inlineJsxTransform',

filename: compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
patch: @@ -50,6 +50,13 @@ import {
 import {Scope as BabelScope} from '@babel/traverse';
 import {TypeSchema} from './TypeSchema';
 
+export const ReactElementSymbolSchema = z.object({
+  elementSymbol: z.union([
+    z.literal('react.element'),
+    z.literal('react.transitional.element'),
+  ]),
+});
+
 export const ExternalFunctionSchema = z.object({
   // Source for the imported module that exports the `importSpecifierName` functions
   source: z.string(),
@@ -237,8 +244,10 @@ const EnvironmentConfigSchema = z.object({
    * Enables inlining ReactElement object literals in place of JSX
    * An alternative to the standard JSX transform which replaces JSX with React's jsxProd() runtime
    * Currently a prod-only optimization, requiring Fast JSX dependencies
+   *
+   * The symbol configuration is set for backwards compatability with pre-React 19 transforms
    */
-  enableInlineJsxTransform: z.boolean().default(false),
+  inlineJsxTransform: ReactElementSymbolSchema.nullish(),
 
   /*
    * Enable validation of hooks to partially check that the component honors the rules of hooks.

filename: compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts
patch: @@ -23,7 +23,7 @@ import {
   markPredecessors,
   reversePostorderBlocks,
 } from '../HIR/HIRBuilder';
-import {CompilerError} from '..';
+import {CompilerError, EnvironmentConfig} from '..';
 
 function createSymbolProperty(
   fn: HIRFunction,
@@ -316,7 +316,12 @@ function createPropsProperties(
 }
 
 // TODO: Make PROD only with conditional statements
-export function inlineJsxTransform(fn: HIRFunction): void {
+export function inlineJsxTransform(
+  fn: HIRFunction,
+  inlineJsxTransformConfig: NonNullable<
+    EnvironmentConfig['inlineJsxTransform']
+  >,
+): void {
   for (const [, block] of fn.body.blocks) {
     let nextInstructions: Array<Instruction> | null = null;
     for (let i = 0; i < block.instructions.length; i++) {
@@ -344,11 +349,7 @@ export function inlineJsxTransform(fn: HIRFunction): void {
                   instr,
                   nextInstructions,
                   '$$typeof',
-                  /**
-                   * TODO: Add this to config so we can switch between
-                   * react.element / react.transitional.element
-                   */
-                  'react.transitional.element',
+                  inlineJsxTransformConfig.elementSymbol,
                 ),
                 createTagProperty(fn, instr, nextInstructions, instr.value.tag),
                 refProperty,
@@ -384,11 +385,7 @@ export function inlineJsxTransform(fn: HIRFunction): void {
                   instr,
                   nextInstructions,
                   '$$typeof',
-                  /**
-                   * TODO: Add this to config so we can switch between
-                   * react.element / react.transitional.element
-                   */
-                  'react.transitional.element',
+                  inlineJsxTransformConfig.elementSymbol,
                 ),
                 createSymbolProperty(
                   fn,

filename: compiler/packages/snap/src/compiler.ts
patch: @@ -21,6 +21,7 @@ import type {
 } from 'babel-plugin-react-compiler/src/Entrypoint';
 import type {Effect, ValueKind} from 'babel-plugin-react-compiler/src/HIR';
 import type {
+  EnvironmentConfig,
   Macro,
   MacroMethod,
   parseConfigPragma as ParseConfigPragma,
@@ -201,6 +202,11 @@ function makePluginOptions(
     };
   }
 
+  let inlineJsxTransform: EnvironmentConfig['inlineJsxTransform'] = null;
+  if (firstLine.includes('@enableInlineJsxTransform')) {
+    inlineJsxTransform = {elementSymbol: 'react.transitional.element'};
+  }
+
   let logs: Array<{filename: string | null; event: LoggerEvent}> = [];
   let logger: Logger | null = null;
   if (firstLine.includes('@logger')) {
@@ -230,6 +236,7 @@ function makePluginOptions(
       enableChangeDetectionForDebugging,
       lowerContextAccess,
       validateBlocklistedImports,
+      inlineJsxTransform,
     },
     compilationMode,
     logger,