[compiler] InlineJSXTransform transforms jsx inside function expressions (#31282)
InlineJSXTransform wasn't traversing into function expressions or object methods, so any JSX inside such functions wouldn't have gotten inlined. This PR updates to traverse nested functions to transform all JSX within a hook or component. Note that this still doesn't transform JSX outside of components or hooks, ie in standalone render helpers.
Joseph Savona committed
Oct 18, 2024 at 11:27 UTC
cdde15efe189e8bebe227b7555e7cc95ad74deab
3 files changed
+83
-34
compiler/packages/babel-plugin-react-compiler/src/Optimization/InlineJsxTransform.ts
+11
@@ -405,6 +405,17 @@ export function inlineJsxTransform(
405
nextInstructions.push(reactElementInstruction);
406
break;
407
}
408
+ case 'FunctionExpression':
409
+ case 'ObjectMethod': {
410
+ inlineJsxTransform(
411
+ instr.value.loweredFunc.func,
412
+ inlineJsxTransformConfig,
413
+ );
414
+ if (nextInstructions !== null) {
415
+ nextInstructions.push(instr);
416
+ }
417
+ break;
418
+ }
419
default: {
420
if (nextInstructions !== null) {
421
nextInstructions.push(instr);
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.expect.md
+65
-31
@@ -26,11 +26,15 @@ function ParentAndRefAndKey(props) {
26
}
27
28
function ParentAndChildren(props) {
29
+ const render = () => {
30
+ return <div key="d">{props.foo}</div>;
31
+ };
32
return (
33
<Parent>
34
<Child key="a" {...props} />
35
<Child key="b">
33
- <GrandChild className={props.foo} {...props} />
36
+ <GrandChild key="c" className={props.foo} {...props} />
37
+ {render()}
38
</Child>
39
</Parent>
40
);
@@ -40,8 +44,8 @@ const propsToSpread = {a: 'a', b: 'b', c: 'c'};
44
function PropsSpread() {
45
return (
46
<>
43
- <Test {...propsToSpread} />
44
- <Test {...propsToSpread} a="z" />
47
+ <Test key="a" {...propsToSpread} />
48
+ <Test key="b" {...propsToSpread} a="z" />
49
</>
50
);
51
}
@@ -151,37 +155,30 @@ function ParentAndRefAndKey(props) {
155
}
156
157
function ParentAndChildren(props) {
154
- const $ = _c2(7);
158
+ const $ = _c2(14);
159
let t0;
156
- if ($[0] !== props) {
157
- t0 = {
160
+ if ($[0] !== props.foo) {
161
+ t0 = () => ({
162
$$typeof: Symbol.for("react.transitional.element"),
159
- type: Child,
163
+ type: "div",
164
ref: null,
161
- key: "a",
162
- props: props,
163
- };
164
- $[0] = props;
165
+ key: "d",
166
+ props: { children: props.foo },
167
+ });
168
+ $[0] = props.foo;
169
$[1] = t0;
170
} else {
171
t0 = $[1];
172
}
173
+ const render = t0;
174
let t1;
175
if ($[2] !== props) {
176
t1 = {
177
$$typeof: Symbol.for("react.transitional.element"),
178
type: Child,
179
ref: null,
175
- key: "b",
176
- props: {
177
- children: {
178
- $$typeof: Symbol.for("react.transitional.element"),
179
- type: GrandChild,
180
- ref: null,
181
- key: null,
182
- props: { className: props.foo, ...props },
183
- },
184
- },
180
+ key: "a",
181
+ props: props,
182
};
183
$[2] = props;
184
$[3] = t1;
@@ -189,21 +186,58 @@ function ParentAndChildren(props) {
186
t1 = $[3];
187
}
188
let t2;
192
- if ($[4] !== t0 || $[5] !== t1) {
189
+ if ($[4] !== props) {
190
t2 = {
191
+ $$typeof: Symbol.for("react.transitional.element"),
192
+ type: GrandChild,
193
+ ref: null,
194
+ key: "c",
195
+ props: { className: props.foo, ...props },
196
+ };
197
+ $[4] = props;
198
+ $[5] = t2;
199
+ } else {
200
+ t2 = $[5];
201
+ }
202
+ let t3;
203
+ if ($[6] !== render) {
204
+ t3 = render();
205
+ $[6] = render;
206
+ $[7] = t3;
207
+ } else {
208
+ t3 = $[7];
209
+ }
210
+ let t4;
211
+ if ($[8] !== t2 || $[9] !== t3) {
212
+ t4 = {
213
+ $$typeof: Symbol.for("react.transitional.element"),
214
+ type: Child,
215
+ ref: null,
216
+ key: "b",
217
+ props: { children: [t2, t3] },
218
+ };
219
+ $[8] = t2;
220
+ $[9] = t3;
221
+ $[10] = t4;
222
+ } else {
223
+ t4 = $[10];
224
+ }
225
+ let t5;
226
+ if ($[11] !== t1 || $[12] !== t4) {
227
+ t5 = {
228
$$typeof: Symbol.for("react.transitional.element"),
229
type: Parent,
230
ref: null,
231
key: null,
198
- props: { children: [t0, t1] },
232
+ props: { children: [t1, t4] },
233
};
200
- $[4] = t0;
201
- $[5] = t1;
202
- $[6] = t2;
234
+ $[11] = t1;
235
+ $[12] = t4;
236
+ $[13] = t5;
237
} else {
204
- t2 = $[6];
238
+ t5 = $[13];
239
}
206
- return t2;
240
+ return t5;
241
}
242
243
const propsToSpread = { a: "a", b: "b", c: "c" };
@@ -222,14 +256,14 @@ function PropsSpread() {
256
$$typeof: Symbol.for("react.transitional.element"),
257
type: Test,
258
ref: null,
225
- key: null,
259
+ key: "a",
260
props: propsToSpread,
261
},
262
{
263
$$typeof: Symbol.for("react.transitional.element"),
264
type: Test,
265
ref: null,
232
- key: null,
266
+ key: "b",
267
props: { ...propsToSpread, a: "z" },
268
},
269
],
@@ -250,4 +284,4 @@ export const FIXTURE_ENTRYPOINT = {
284
```
285
286
### Eval output
253
-(kind: ok) <div><span class="abc">Hello world</span></div>
\ No newline at end of file
287
+(kind: ok) <div><span class="abc">Hello world</span><div>abc</div></div>
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/inline-jsx-transform.js
+7
-3
@@ -22,11 +22,15 @@ function ParentAndRefAndKey(props) {
22
}
23
24
function ParentAndChildren(props) {
25
+ const render = () => {
26
+ return <div key="d">{props.foo}</div>;
27
+ };
28
return (
29
<Parent>
30
<Child key="a" {...props} />
31
<Child key="b">
29
- <GrandChild className={props.foo} {...props} />
32
+ <GrandChild key="c" className={props.foo} {...props} />
33
+ {render()}
34
</Child>
35
</Parent>
36
);
@@ -36,8 +40,8 @@ const propsToSpread = {a: 'a', b: 'b', c: 'c'};
40
function PropsSpread() {
41
return (
42
<>
39
- <Test {...propsToSpread} />
40
- <Test {...propsToSpread} a="z" />
43
+ <Test key="a" {...propsToSpread} />
44
+ <Test key="b" {...propsToSpread} a="z" />
45
</>
46
);
47
}