From 632f88df11329c9ad66781ddd75b27df6f8effb9 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Thu, 19 Sep 2024 10:34:24 -0400 Subject: [PATCH] [compiler] Allow ReactElement symbol to be configured when inlining jsx (#30996) 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. --- .../src/Entrypoint/Pipeline.ts | 4 ++-- .../src/HIR/Environment.ts | 11 +++++++++- .../src/Optimization/InlineJsxTransform.ts | 21 ++++++++----------- compiler/packages/snap/src/compiler.ts | 7 +++++++ 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts index 606440b241f9b..900e4f4908494 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts @@ -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', diff --git a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts index 66270345fdf35..50905bc581dc1 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts @@ -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. diff --git a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts index 0fe516da977e3..396e6ad1be8dc 100644 --- a/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts +++ b/compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts @@ -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 | 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, diff --git a/compiler/packages/snap/src/compiler.ts b/compiler/packages/snap/src/compiler.ts index 417a657d28012..bbb6aeded750c 100644 --- a/compiler/packages/snap/src/compiler.ts +++ b/compiler/packages/snap/src/compiler.ts @@ -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,