@samitouri / QOS-React / commits / 632f88df11

[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,