@samitouri / QOS-React / commits / cdde15efe1

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