[compiler] Always emit variable decl in gating mode
This PR makes it so we always emit a const VariableDeclaration for compiled functions in gating mode. If the original declaration's parent was an ExportDefaultDeclaration we'll also append a new ExportDefaultDeclaration pointing to the new identifier. This allows code that adds optional properties to the function declaration to still work in gating mode ghstack-source-id: 5705479135baa268eeb3c85bfbf1883964e84916 Pull Request resolved: https://github.com/facebook/react/pull/29806
Lauren Tan committed
Jun 7, 2024 at 15:39 UTC
20841f9a6205a633e6d08a274db974481daaca23
6 files changed
+32
-31
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Gating.ts
+20
-7
@@ -18,14 +18,13 @@ export function insertGatedFunctionDeclaration(
18
| t.ArrowFunctionExpression
19
| t.FunctionExpression,
20
gating: NonNullable<PluginOptions["gating"]>
21
-): NodePath<t.ConditionalExpression | t.VariableDeclaration> {
21
+): void {
22
const gatingExpression = t.conditionalExpression(
23
t.callExpression(t.identifier(gating.importSpecifierName), []),
24
buildFunctionExpression(compiled),
25
buildFunctionExpression(fnPath.node)
26
);
27
28
- let compiledFn;
28
/*
29
* Convert function declarations to named variables *unless* this is an
30
* `export default function ...` since `export default const ...` is
@@ -37,16 +36,30 @@ export function insertGatedFunctionDeclaration(
36
fnPath.node.type === "FunctionDeclaration" &&
37
fnPath.node.id != null
38
) {
40
- compiledFn = fnPath.replaceWith(
39
+ fnPath.replaceWith(
40
t.variableDeclaration("const", [
41
t.variableDeclarator(fnPath.node.id, gatingExpression),
42
])
44
- )[0];
43
+ );
44
+ } else if (
45
+ fnPath.parentPath.node.type === "ExportDefaultDeclaration" &&
46
+ fnPath.node.type !== "ArrowFunctionExpression" &&
47
+ fnPath.node.id != null
48
+ ) {
49
+ fnPath.insertAfter(
50
+ t.exportDefaultDeclaration(t.identifier(fnPath.node.id.name))
51
+ );
52
+ fnPath.parentPath.replaceWith(
53
+ t.variableDeclaration("const", [
54
+ t.variableDeclarator(
55
+ t.identifier(fnPath.node.id.name),
56
+ gatingExpression
57
+ ),
58
+ ])
59
+ );
60
} else {
46
- compiledFn = fnPath.replaceWith(gatingExpression)[0];
61
+ fnPath.replaceWith(gatingExpression);
62
}
48
-
49
- return compiledFn;
63
}
64
65
function buildFunctionExpression(
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating-preserves-function-properties.expect.md
renamed
+7
-15
@@ -4,11 +4,6 @@
4
```javascript
5
// @gating
6
7
-/**
8
- * Fail: bug-gating-invalid-function-properties
9
- * Unexpected error in Forget runner
10
- * Component is not defined
11
- */
7
export default function Component() {
8
return <></>;
9
}
@@ -23,7 +18,7 @@ Component2.displayName = "Component TWO";
18
export const FIXTURE_ENTRYPOINT = {
19
fn: Component,
20
params: [],
26
- sequentialRenders: [],
21
+ sequentialRenders: [{}],
22
};
23
24
```
@@ -33,13 +28,7 @@ export const FIXTURE_ENTRYPOINT = {
28
```javascript
29
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
30
import { c as _c } from "react/compiler-runtime"; // @gating
36
-
37
-/**
38
- * Fail: bug-gating-invalid-function-properties
39
- * Unexpected error in Forget runner
40
- * Component is not defined
41
- */
42
-export default isForgetEnabled_Fixtures()
31
+const Component = isForgetEnabled_Fixtures()
32
? function Component() {
33
const $ = _c(1);
34
let t0;
@@ -54,6 +43,7 @@ export default isForgetEnabled_Fixtures()
43
: function Component() {
44
return <></>;
45
};
46
+export default Component;
47
48
export const Component2 = isForgetEnabled_Fixtures()
49
? function Component2() {
@@ -77,8 +67,10 @@ Component2.displayName = "Component TWO";
67
export const FIXTURE_ENTRYPOINT = {
68
fn: Component,
69
params: [],
80
- sequentialRenders: [],
70
+ sequentialRenders: [{}],
71
};
72
73
```
84
-
\ No newline at end of file
74
+
75
+### Eval output
76
+(kind: ok)
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating-preserves-function-properties.tsx
renamed
+1
-6
@@ -1,10 +1,5 @@
1
// @gating
2
3
-/**
4
- * Fail: bug-gating-invalid-function-properties
5
- * Unexpected error in Forget runner
6
- * Component is not defined
7
- */
3
export default function Component() {
4
return <></>;
5
}
@@ -19,5 +14,5 @@ Component2.displayName = "Component TWO";
14
export const FIXTURE_ENTRYPOINT = {
15
fn: Component,
16
params: [],
22
- sequentialRenders: [],
17
+ sequentialRenders: [{}],
18
};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating-test-export-default-function.expect.md
+2
-1
@@ -24,7 +24,7 @@ function Foo(props) {
24
```javascript
25
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
26
import { c as _c } from "react/compiler-runtime"; // @gating @compilationMode(annotation)
27
-export default isForgetEnabled_Fixtures()
27
+const Bar = isForgetEnabled_Fixtures()
28
? function Bar(props) {
29
"use forget";
30
const $ = _c(2);
@@ -42,6 +42,7 @@ export default isForgetEnabled_Fixtures()
42
"use forget";
43
return <div>{props.bar}</div>;
44
};
45
+export default Bar;
46
47
function NoForget(props) {
48
return <Bar>{props.noForget}</Bar>;
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating-test-export-function-and-default.expect.md
+2
-1
@@ -24,7 +24,7 @@ export function Foo(props) {
24
```javascript
25
import { isForgetEnabled_Fixtures } from "ReactForgetFeatureFlag";
26
import { c as _c } from "react/compiler-runtime"; // @gating @compilationMode(annotation)
27
-export default isForgetEnabled_Fixtures()
27
+const Bar = isForgetEnabled_Fixtures()
28
? function Bar(props) {
29
"use forget";
30
const $ = _c(2);
@@ -42,6 +42,7 @@ export default isForgetEnabled_Fixtures()
42
"use forget";
43
return <div>{props.bar}</div>;
44
};
45
+export default Bar;
46
47
function NoForget(props) {
48
return <Bar>{props.noForget}</Bar>;
compiler/packages/snap/src/SproutTodoFilter.ts
-1
@@ -490,7 +490,6 @@ const skipFilter = new Set([
490
"bug-invalid-hoisting-functionexpr",
491
"original-reactive-scopes-fork/bug-nonmutating-capture-in-unsplittable-memo-block",
492
"original-reactive-scopes-fork/bug-hoisted-declaration-with-scope",
493
- "bug-gating-invalid-function-properties",
493
494
// 'react-compiler-runtime' not yet supported
495
"flag-enable-emit-hook-guards",