[babel] Fix export ordering
Turns out hoisting doesn't work with export declarations, so fix ordering such that the export always comes after the synthesized test declaration.
Lauren Tan committed
Mar 8, 2023 at 11:42 UTC
0363648178fcf26b806d6e588088707f76c4a75c
5 files changed
+24
-25
compiler/forget/src/Babel/BabelPlugin.ts
+14
-15
@@ -45,7 +45,7 @@ export default function ReactForgetBabelPlugin(
45
FunctionDeclaration(
46
fn: BabelCore.NodePath<t.FunctionDeclaration>,
47
pass: BabelPluginPass
48
- ) {
48
+ ): void {
49
if (pass.opts.enableOnlyOnUseForgetDirective) {
50
if (!hasUseForgetDirective(fn.node.body.directives)) {
51
return;
@@ -80,23 +80,22 @@ export default function ReactForgetBabelPlugin(
80
});
81
82
// Re-export new declaration
83
- const parent = fn.parent;
83
+ const parent = fn.parentPath;
84
if (t.isExportDefaultDeclaration(parent)) {
85
// Re-add uncompiled function
86
- fn.insertAfter(fn.node)[0].skip();
86
+ parent.replaceWith(fn)[0].skip();
87
88
- // Add test
89
- compiledFn.insertAfter(test);
90
-
91
- // Update declartion to original id
92
- parent.declaration = original;
88
+ // Add test and synthesize new export
89
+ compiledFn.insertAfter([
90
+ test,
91
+ t.exportDefaultDeclaration(original),
92
+ ]);
93
} else if (t.isExportNamedDeclaration(parent)) {
94
- invariant(parent.declaration !== null, "");
94
// Re-add uncompiled function
96
- fn.insertAfter(fn.node)[0].skip();
95
+ parent.replaceWith(fn)[0].skip();
96
98
- // Update declartion to test
99
- parent.declaration = test;
97
+ // Add and export test
98
+ compiledFn.insertAfter(t.exportNamedDeclaration(test));
99
} else {
100
// Just add the test, no need for re-export
101
compiledFn.insertAfter(test);
@@ -126,7 +125,7 @@ export default function ReactForgetBabelPlugin(
125
// Note: Babel does some "smart" merging of visitors across plugins, so even if A is inserted
126
// prior to B, if A does not have a Program visitor and B does, B will run first. We always
127
// want Forget to run true to source as possible.
129
- Program(path, pass) {
128
+ Program(path, pass): void {
129
const options = parsePluginOptions(pass.opts);
130
try {
131
path.traverse(visitor, {
@@ -159,8 +158,8 @@ function buildTest(ids: {
158
uncompiled: t.Identifier;
159
compiled: t.Identifier;
160
original: t.Identifier;
162
-}): t.Declaration {
163
- return t.variableDeclaration("var", [
161
+}): t.VariableDeclaration {
162
+ return t.variableDeclaration("const", [
163
t.variableDeclarator(
164
ids.original,
165
t.conditionalExpression(testId, ids.compiled, ids.uncompiled)
compiler/forget/src/__tests__/fixtures/hir/gating-test-export-default-function.expect.md
+3
-3
@@ -23,7 +23,6 @@ function Foo(props) {
23
24
```javascript
25
import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule @forgetDirective
26
-export default Bar;
26
function Bar_uncompiled(props) {
27
"use forget";
28
return <div>{props.bar}</div>;
@@ -41,7 +40,8 @@ function Bar_forget(props) {
40
}
41
return t0;
42
}
44
-var Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled;
43
+const Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled;
44
+export default Bar;
45
46
function NoForget(props) {
47
return <Bar>{props.noForget}</Bar>;
@@ -64,7 +64,7 @@ function Foo_forget(props) {
64
}
65
return t0;
66
}
67
-var Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled;
67
+const Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled;
68
69
```
70
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function-and-default.expect.md
+3
-3
@@ -23,7 +23,6 @@ export function Foo(props) {
23
24
```javascript
25
import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule @forgetDirective
26
-export default Bar;
26
function Bar_uncompiled(props) {
27
"use forget";
28
return <div>{props.bar}</div>;
@@ -41,13 +40,13 @@ function Bar_forget(props) {
40
}
41
return t0;
42
}
44
-var Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled;
43
+const Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled;
44
+export default Bar;
45
46
function NoForget(props) {
47
return <Bar>{props.noForget}</Bar>;
48
}
49
50
-export var Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled;
50
function Foo_uncompiled(props) {
51
"use forget";
52
return <Foo>{props.bar}</Foo>;
@@ -65,6 +64,7 @@ function Foo_forget(props) {
64
}
65
return t0;
66
}
67
+export const Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled;
68
69
```
70
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/gating-test-export-function.expect.md
+2
-2
@@ -23,7 +23,6 @@ export function Foo(props) {
23
24
```javascript
25
import isForgetEnabled from "ReactForgetFeatureFlag"; // @gatingModule @forgetDirective
26
-export var Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled;
26
function Bar_uncompiled(props) {
27
"use forget";
28
return <div>{props.bar}</div>;
@@ -41,12 +40,12 @@ function Bar_forget(props) {
40
}
41
return t0;
42
}
43
+export const Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled;
44
45
export function NoForget(props) {
46
return <Bar>{props.noForget}</Bar>;
47
}
48
49
-export var Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled;
49
function Foo_uncompiled(props) {
50
"use forget";
51
return <Foo>{props.bar}</Foo>;
@@ -64,6 +63,7 @@ function Foo_forget(props) {
63
}
64
return t0;
65
}
66
+export const Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled;
67
68
```
69
\ No newline at end of file
compiler/forget/src/__tests__/fixtures/hir/gating-test.expect.md
+2
-2
@@ -40,7 +40,7 @@ function Bar_forget(props) {
40
}
41
return t0;
42
}
43
-var Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled;
43
+const Bar = isForgetEnabled ? Bar_forget : Bar_uncompiled;
44
45
function NoForget(props) {
46
return <Bar>{props.noForget}</Bar>;
@@ -63,7 +63,7 @@ function Foo_forget(props) {
63
}
64
return t0;
65
}
66
-var Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled;
66
+const Foo = isForgetEnabled ? Foo_forget : Foo_uncompiled;
67
68
```
69
\ No newline at end of file