[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.
Jack Pope committed
Sep 19, 2024 at 10:34 UTC
632f88df11329c9ad66781ddd75b27df6f8effb9
4 files changed
+28
-15
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+2
-2
@@ -352,8 +352,8 @@ function* runWithEnvironment(
352
});
353
}
354
355
- if (env.config.enableInlineJsxTransform) {
356
- inlineJsxTransform(hir);
355
+ if (env.config.inlineJsxTransform) {
356
+ inlineJsxTransform(hir, env.config.inlineJsxTransform);
357
yield log({
358
kind: 'hir',
359
name: 'inlineJsxTransform',
compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
+10
-1
@@ -50,6 +50,13 @@ import {
50
import {Scope as BabelScope} from '@babel/traverse';
51
import {TypeSchema} from './TypeSchema';
52
53
+export const ReactElementSymbolSchema = z.object({
54
+ elementSymbol: z.union([
55
+ z.literal('react.element'),
56
+ z.literal('react.transitional.element'),
57
+ ]),
58
+});
59
+
60
export const ExternalFunctionSchema = z.object({
61
// Source for the imported module that exports the `importSpecifierName` functions
62
source: z.string(),
@@ -237,8 +244,10 @@ const EnvironmentConfigSchema = z.object({
244
* Enables inlining ReactElement object literals in place of JSX
245
* An alternative to the standard JSX transform which replaces JSX with React's jsxProd() runtime
246
* Currently a prod-only optimization, requiring Fast JSX dependencies
247
+ *
248
+ * The symbol configuration is set for backwards compatability with pre-React 19 transforms
249
*/
241
- enableInlineJsxTransform: z.boolean().default(false),
250
+ inlineJsxTransform: ReactElementSymbolSchema.nullish(),
251
252
/*
253
* Enable validation of hooks to partially check that the component honors the rules of hooks.
compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts
+9
-12
@@ -23,7 +23,7 @@ import {
23
markPredecessors,
24
reversePostorderBlocks,
25
} from '../HIR/HIRBuilder';
26
-import {CompilerError} from '..';
26
+import {CompilerError, EnvironmentConfig} from '..';
27
28
function createSymbolProperty(
29
fn: HIRFunction,
@@ -316,7 +316,12 @@ function createPropsProperties(
316
}
317
318
// TODO: Make PROD only with conditional statements
319
-export function inlineJsxTransform(fn: HIRFunction): void {
319
+export function inlineJsxTransform(
320
+ fn: HIRFunction,
321
+ inlineJsxTransformConfig: NonNullable<
322
+ EnvironmentConfig['inlineJsxTransform']
323
+ >,
324
+): void {
325
for (const [, block] of fn.body.blocks) {
326
let nextInstructions: Array<Instruction> | null = null;
327
for (let i = 0; i < block.instructions.length; i++) {
@@ -344,11 +349,7 @@ export function inlineJsxTransform(fn: HIRFunction): void {
349
instr,
350
nextInstructions,
351
'$$typeof',
347
- /**
348
- * TODO: Add this to config so we can switch between
349
- * react.element / react.transitional.element
350
- */
351
- 'react.transitional.element',
352
+ inlineJsxTransformConfig.elementSymbol,
353
),
354
createTagProperty(fn, instr, nextInstructions, instr.value.tag),
355
refProperty,
@@ -384,11 +385,7 @@ export function inlineJsxTransform(fn: HIRFunction): void {
385
instr,
386
nextInstructions,
387
'$$typeof',
387
- /**
388
- * TODO: Add this to config so we can switch between
389
- * react.element / react.transitional.element
390
- */
391
- 'react.transitional.element',
388
+ inlineJsxTransformConfig.elementSymbol,
389
),
390
createSymbolProperty(
391
fn,
compiler/packages/snap/src/compiler.ts
+7
@@ -21,6 +21,7 @@ import type {
21
} from 'babel-plugin-react-compiler/src/Entrypoint';
22
import type {Effect, ValueKind} from 'babel-plugin-react-compiler/src/HIR';
23
import type {
24
+ EnvironmentConfig,
25
Macro,
26
MacroMethod,
27
parseConfigPragma as ParseConfigPragma,
@@ -201,6 +202,11 @@ function makePluginOptions(
202
};
203
}
204
205
+ let inlineJsxTransform: EnvironmentConfig['inlineJsxTransform'] = null;
206
+ if (firstLine.includes('@enableInlineJsxTransform')) {
207
+ inlineJsxTransform = {elementSymbol: 'react.transitional.element'};
208
+ }
209
+
210
let logs: Array<{filename: string | null; event: LoggerEvent}> = [];
211
let logger: Logger | null = null;
212
if (firstLine.includes('@logger')) {
@@ -230,6 +236,7 @@ function makePluginOptions(
236
enableChangeDetectionForDebugging,
237
lowerContextAccess,
238
validateBlocklistedImports,
239
+ inlineJsxTransform,
240
},
241
compilationMode,
242
logger,