mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[Babel] Desugar ArrowFunctionExpression
Rewrite ArrowFunctionExpression to FunctionDeclaration and compile it. This lets us reuse all the export gating logic, rather than writing separate, specific logic for ArrowFunctionExpression.
This commit is contained in:
@@ -80,6 +80,17 @@ export default function ReactForgetBabelPlugin(
|
||||
|
||||
visitFn(fn, pass);
|
||||
},
|
||||
|
||||
ArrowFunctionExpression(
|
||||
fn: BabelCore.NodePath<t.ArrowFunctionExpression>,
|
||||
pass: BabelPluginPass
|
||||
): void {
|
||||
if (!shouldCompile(fn, pass)) {
|
||||
return;
|
||||
}
|
||||
|
||||
visitFn(buildFunctionDeclaration(fn), pass);
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
@@ -135,6 +146,54 @@ function shouldCompile(
|
||||
return true;
|
||||
}
|
||||
|
||||
function buildFunctionDeclaration(
|
||||
fn: BabelCore.NodePath<t.ArrowFunctionExpression>
|
||||
): BabelCore.NodePath<t.FunctionDeclaration> {
|
||||
invariant(
|
||||
fn.parentPath.isVariableDeclarator(),
|
||||
"ArrowFunctionExpression must be declared in variable declaration"
|
||||
);
|
||||
const variableDeclarator = fn.parentPath;
|
||||
|
||||
invariant(
|
||||
variableDeclarator.parentPath.isVariableDeclaration(),
|
||||
"ArrowFunctionExpression must be a single declaration"
|
||||
);
|
||||
const variableDeclaration = variableDeclarator.parentPath;
|
||||
|
||||
const id = variableDeclarator.get("id");
|
||||
invariant(id.isIdentifier(), "ArrowFunctionExpression must have an id");
|
||||
|
||||
const rewrittenFn = variableDeclaration.replaceWith(
|
||||
t.functionDeclaration(
|
||||
id.node,
|
||||
fn.node.params,
|
||||
buildBlockStatement(fn),
|
||||
fn.node.generator,
|
||||
fn.node.async
|
||||
)
|
||||
)[0];
|
||||
fn.skip();
|
||||
return rewrittenFn;
|
||||
}
|
||||
|
||||
function buildBlockStatement(
|
||||
fn: BabelCore.NodePath<t.ArrowFunctionExpression>
|
||||
): t.BlockStatement {
|
||||
const body = fn.get("body");
|
||||
if (body.isExpression()) {
|
||||
const wrappedBody = body.replaceWith(
|
||||
t.blockStatement([t.returnStatement(body.node)])
|
||||
)[0];
|
||||
body.skip();
|
||||
|
||||
return wrappedBody.node;
|
||||
}
|
||||
|
||||
invariant(body.isBlockStatement(), "Body must be a BlockStatement");
|
||||
return body.node;
|
||||
}
|
||||
|
||||
function buildGatingTest(
|
||||
uncompiled: BabelCore.NodePath<t.FunctionDeclaration>,
|
||||
compiled: t.Identifier,
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gatingModule
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export default ErrorView;
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule
|
||||
function ErrorView_uncompiled(error, _retry) {
|
||||
return <MessageBox error={error}></MessageBox>;
|
||||
}
|
||||
function ErrorView_forget(error, _retry) {
|
||||
const $ = React.unstable_useMemoCache(2);
|
||||
const c_0 = $[0] !== error;
|
||||
let t0;
|
||||
if (c_0) {
|
||||
t0 = <MessageBox error={error}></MessageBox>;
|
||||
$[0] = error;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
const ErrorView = isForgetEnabled ? ErrorView_forget : ErrorView_uncompiled;
|
||||
|
||||
export default ErrorView;
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// @gatingModule
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export default ErrorView;
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gatingModule
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export default Renderer = (props) => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Error
|
||||
|
||||
```
|
||||
ArrowFunctionExpression must be declared in variable declaration
|
||||
```
|
||||
|
||||
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// @gatingModule
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export default Renderer = (props) => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gatingModule
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export const Renderer = (props) => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule
|
||||
function ErrorView_uncompiled(error, _retry) {
|
||||
return <MessageBox error={error}></MessageBox>;
|
||||
}
|
||||
function ErrorView_forget(error, _retry) {
|
||||
const $ = React.unstable_useMemoCache(2);
|
||||
const c_0 = $[0] !== error;
|
||||
let t0;
|
||||
if (c_0) {
|
||||
t0 = <MessageBox error={error}></MessageBox>;
|
||||
$[0] = error;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
const ErrorView = isForgetEnabled ? ErrorView_forget : ErrorView_uncompiled;
|
||||
function Renderer_uncompiled(props) {
|
||||
return (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
}
|
||||
function Renderer_forget(props) {
|
||||
const $ = React.unstable_useMemoCache(3);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <Bar></Bar>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <ErrorView></ErrorView>;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
let t2;
|
||||
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t2 = (
|
||||
<Foo>
|
||||
{t0}
|
||||
{t1}
|
||||
</Foo>
|
||||
);
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
export const Renderer = isForgetEnabled ? Renderer_forget : Renderer_uncompiled;
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// @gatingModule
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
export const Renderer = (props) => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
|
||||
## Input
|
||||
|
||||
```javascript
|
||||
// @gatingModule
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
const Renderer = (props) => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
|
||||
export default Renderer;
|
||||
|
||||
```
|
||||
|
||||
## Code
|
||||
|
||||
```javascript
|
||||
import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule
|
||||
function ErrorView_uncompiled(error, _retry) {
|
||||
return <MessageBox error={error}></MessageBox>;
|
||||
}
|
||||
function ErrorView_forget(error, _retry) {
|
||||
const $ = React.unstable_useMemoCache(2);
|
||||
const c_0 = $[0] !== error;
|
||||
let t0;
|
||||
if (c_0) {
|
||||
t0 = <MessageBox error={error}></MessageBox>;
|
||||
$[0] = error;
|
||||
$[1] = t0;
|
||||
} else {
|
||||
t0 = $[1];
|
||||
}
|
||||
return t0;
|
||||
}
|
||||
const ErrorView = isForgetEnabled ? ErrorView_forget : ErrorView_uncompiled;
|
||||
function Renderer_uncompiled(props) {
|
||||
return (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
}
|
||||
function Renderer_forget(props) {
|
||||
const $ = React.unstable_useMemoCache(3);
|
||||
let t0;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t0 = <Bar></Bar>;
|
||||
$[0] = t0;
|
||||
} else {
|
||||
t0 = $[0];
|
||||
}
|
||||
let t1;
|
||||
if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t1 = <ErrorView></ErrorView>;
|
||||
$[1] = t1;
|
||||
} else {
|
||||
t1 = $[1];
|
||||
}
|
||||
let t2;
|
||||
if ($[2] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
t2 = (
|
||||
<Foo>
|
||||
{t0}
|
||||
{t1}
|
||||
</Foo>
|
||||
);
|
||||
$[2] = t2;
|
||||
} else {
|
||||
t2 = $[2];
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
const Renderer = isForgetEnabled ? Renderer_forget : Renderer_uncompiled;
|
||||
export default Renderer;
|
||||
|
||||
```
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
// @gatingModule
|
||||
const ErrorView = (error, _retry) => <MessageBox error={error}></MessageBox>;
|
||||
|
||||
const Renderer = (props) => (
|
||||
<Foo>
|
||||
<Bar></Bar>
|
||||
<ErrorView></ErrorView>
|
||||
</Foo>
|
||||
);
|
||||
|
||||
export default Renderer;
|
||||
Reference in New Issue
Block a user