Skip to content

Commit a88b9e5

Browse files
authored
[compiler] Outline JSX with non-jsx children (#31442)
Previously, we bailed out on outlining jsx that had children that were not part of the outlined jsx. Now, we add support for children by treating as attributes.
1 parent 09197bb commit a88b9e5

File tree

3 files changed

+137
-24
lines changed

3 files changed

+137
-24
lines changed

compiler/packages/babel-plugin-react-compiler/src/Optimization/OutlineJsx.ts

+46-12
Original file line numberDiff line numberDiff line change
@@ -219,10 +219,20 @@ type OutlinedJsxAttribute = {
219219
function collectProps(
220220
instructions: Array<JsxInstruction>,
221221
): Array<OutlinedJsxAttribute> | null {
222+
let id = 1;
223+
224+
function generateName(oldName: string): string {
225+
let newName = oldName;
226+
while (seen.has(newName)) {
227+
newName = `${oldName}${id++}`;
228+
}
229+
seen.add(newName);
230+
return newName;
231+
}
232+
222233
const attributes: Array<OutlinedJsxAttribute> = [];
223234
const jsxIds = new Set(instructions.map(i => i.lvalue.identifier.id));
224235
const seen: Set<string> = new Set();
225-
let id = 1;
226236

227237
for (const instr of instructions) {
228238
const {value} = instr;
@@ -233,25 +243,29 @@ function collectProps(
233243
}
234244

235245
if (at.kind === 'JsxAttribute') {
236-
let newName = at.name;
237-
while (seen.has(newName)) {
238-
newName = `${at.name}${id++}`;
239-
}
246+
const newName = generateName(at.name);
240247
attributes.push({
241248
originalName: at.name,
242249
newName,
243250
place: at.place,
244251
});
245-
seen.add(newName);
246252
}
247253
}
248254

249-
// TODO(gsn): Add support for children that are not jsx expressions
250-
if (
251-
value.children &&
252-
value.children.some(child => !jsxIds.has(child.identifier.id))
253-
) {
254-
return null;
255+
if (value.children) {
256+
for (const child of value.children) {
257+
if (jsxIds.has(child.identifier.id)) {
258+
continue;
259+
}
260+
261+
promoteTemporary(child.identifier);
262+
const newName = generateName('t');
263+
attributes.push({
264+
originalName: child.identifier.name!.value,
265+
newName: newName,
266+
place: child,
267+
});
268+
}
255269
}
256270
}
257271
return attributes;
@@ -387,6 +401,7 @@ function emitUpdatedJsx(
387401
oldToNewProps: Map<IdentifierId, OutlinedJsxAttribute>,
388402
): Array<JsxInstruction> {
389403
const newInstrs: Array<JsxInstruction> = [];
404+
const jsxIds = new Set(jsx.map(i => i.lvalue.identifier.id));
390405

391406
for (const instr of jsx) {
392407
const {value} = instr;
@@ -412,11 +427,30 @@ function emitUpdatedJsx(
412427
});
413428
}
414429

430+
let newChildren: Array<Place> | null = null;
431+
if (value.children) {
432+
newChildren = [];
433+
for (const child of value.children) {
434+
if (jsxIds.has(child.identifier.id)) {
435+
newChildren.push({...child});
436+
continue;
437+
}
438+
439+
const newChild = oldToNewProps.get(child.identifier.id);
440+
invariant(
441+
newChild !== undefined,
442+
`Expected a new prop for ${printIdentifier(child.identifier)}`,
443+
);
444+
newChildren.push({...newChild.place});
445+
}
446+
}
447+
415448
newInstrs.push({
416449
...instr,
417450
value: {
418451
...value,
419452
props: newProps,
453+
children: newChildren,
420454
},
421455
});
422456
}
+78-10
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ function Component({arr}) {
1111
return (
1212
<Bar key={id} x={x}>
1313
<Baz i={i}>Test</Baz>
14+
<Foo k={i} />
1415
</Bar>
1516
);
1617
})}
1718
</>
1819
);
1920
}
21+
2022
function Bar({x, children}) {
2123
return (
2224
<>
@@ -26,8 +28,17 @@ function Bar({x, children}) {
2628
);
2729
}
2830

29-
function Baz({i}) {
30-
return i;
31+
function Baz({i, children}) {
32+
return (
33+
<>
34+
{i}
35+
{children}
36+
</>
37+
);
38+
}
39+
40+
function Foo({k}) {
41+
return k;
3142
}
3243

3344
function useX() {
@@ -53,11 +64,11 @@ function Component(t0) {
5364
if ($[0] !== arr || $[1] !== x) {
5465
let t2;
5566
if ($[3] !== x) {
56-
t2 = (i, id) => (
57-
<Bar key={id} x={x}>
58-
<Baz i={i}>Test</Baz>
59-
</Bar>
60-
);
67+
t2 = (i, id) => {
68+
const t3 = "Test";
69+
const T0 = _temp;
70+
return <T0 i={i} t={t3} k={i} key={id} x={x} />;
71+
};
6172
$[3] = x;
6273
$[4] = t2;
6374
} else {
@@ -80,6 +91,43 @@ function Component(t0) {
8091
}
8192
return t2;
8293
}
94+
function _temp(t0) {
95+
const $ = _c(9);
96+
const { i: i, t: t, k: k, x: x } = t0;
97+
let t1;
98+
if ($[0] !== i || $[1] !== t) {
99+
t1 = <Baz i={i}>{t}</Baz>;
100+
$[0] = i;
101+
$[1] = t;
102+
$[2] = t1;
103+
} else {
104+
t1 = $[2];
105+
}
106+
let t2;
107+
if ($[3] !== k) {
108+
t2 = <Foo k={k} />;
109+
$[3] = k;
110+
$[4] = t2;
111+
} else {
112+
t2 = $[4];
113+
}
114+
let t3;
115+
if ($[5] !== t1 || $[6] !== t2 || $[7] !== x) {
116+
t3 = (
117+
<Bar x={x}>
118+
{t1}
119+
{t2}
120+
</Bar>
121+
);
122+
$[5] = t1;
123+
$[6] = t2;
124+
$[7] = x;
125+
$[8] = t3;
126+
} else {
127+
t3 = $[8];
128+
}
129+
return t3;
130+
}
83131

84132
function Bar(t0) {
85133
const $ = _c(3);
@@ -102,8 +150,28 @@ function Bar(t0) {
102150
}
103151

104152
function Baz(t0) {
105-
const { i } = t0;
106-
return i;
153+
const $ = _c(3);
154+
const { i, children } = t0;
155+
let t1;
156+
if ($[0] !== children || $[1] !== i) {
157+
t1 = (
158+
<>
159+
{i}
160+
{children}
161+
</>
162+
);
163+
$[0] = children;
164+
$[1] = i;
165+
$[2] = t1;
166+
} else {
167+
t1 = $[2];
168+
}
169+
return t1;
170+
}
171+
172+
function Foo(t0) {
173+
const { k } = t0;
174+
return k;
107175
}
108176

109177
function useX() {
@@ -118,4 +186,4 @@ export const FIXTURE_ENTRYPOINT = {
118186
```
119187
120188
### Eval output
121-
(kind: ok) xfooxbar
189+
(kind: ok) xfooTestfooxbarTestbar
+13-2
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ function Component({arr}) {
77
return (
88
<Bar key={id} x={x}>
99
<Baz i={i}>Test</Baz>
10+
<Foo k={i} />
1011
</Bar>
1112
);
1213
})}
1314
</>
1415
);
1516
}
17+
1618
function Bar({x, children}) {
1719
return (
1820
<>
@@ -22,8 +24,17 @@ function Bar({x, children}) {
2224
);
2325
}
2426

25-
function Baz({i}) {
26-
return i;
27+
function Baz({i, children}) {
28+
return (
29+
<>
30+
{i}
31+
{children}
32+
</>
33+
);
34+
}
35+
36+
function Foo({k}) {
37+
return k;
2738
}
2839

2940
function useX() {

0 commit comments

Comments
 (0)