Skip to content

Commit 1b1283a

Browse files
authored
[compiler] Support default imports for autodep config (facebook#31657)
## Summary Allows us to add deps for things like `import useWrapperEffect from 'useWrapperEffect'` --- [//]: # (BEGIN SAPLING FOOTER) Stack created with [Sapling](https://sapling-scm.com). Best reviewed with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31657). * __->__ facebook#31657 * facebook#31652
1 parent 2ab471c commit 1b1283a

File tree

7 files changed

+67
-4
lines changed

7 files changed

+67
-4
lines changed

compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,13 @@ const testComplexConfigDefaults: PartialEnvironmentConfig = {
660660
},
661661
numRequiredArgs: 2,
662662
},
663+
{
664+
function: {
665+
source: 'useEffectWrapper',
666+
importSpecifierName: 'default',
667+
},
668+
numRequiredArgs: 1,
669+
},
663670
],
664671
};
665672

@@ -1147,3 +1154,5 @@ export function tryParseExternalFunction(
11471154
suggestions: null,
11481155
});
11491156
}
1157+
1158+
export const DEFAULT_EXPORT = 'default';

compiler/packages/babel-plugin-react-compiler/src/Inference/InferEffectDependencies.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
Place,
1717
ReactiveScopeDependencies,
1818
} from '../HIR';
19+
import {DEFAULT_EXPORT} from '../HIR/Environment';
1920
import {
2021
createTemporaryPlace,
2122
fixScopeAndIdentifierRanges,
@@ -97,6 +98,17 @@ export function inferEffectDependencies(fn: HIRFunction): void {
9798
autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
9899
}
99100
}
101+
} else if (
102+
value.kind === 'LoadGlobal' &&
103+
value.binding.kind === 'ImportDefault'
104+
) {
105+
const moduleTargets = autodepFnConfigs.get(value.binding.module);
106+
if (moduleTargets != null) {
107+
const numRequiredArgs = moduleTargets.get(DEFAULT_EXPORT);
108+
if (numRequiredArgs != null) {
109+
autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
110+
}
111+
}
100112
} else if (
101113
/*
102114
* TODO: Handle method calls

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies.expect.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
```javascript
55
// @inferEffectDependencies
66
import {useEffect, useRef} from 'react';
7+
import useEffectWrapper from 'useEffectWrapper';
78

89
const moduleNonReactive = 0;
910

@@ -39,6 +40,10 @@ function Component({foo, bar}) {
3940

4041
// No inferred dep array, the argument is not a lambda
4142
useEffect(f);
43+
44+
useEffectWrapper(() => {
45+
console.log(foo);
46+
});
4247
}
4348

4449
```
@@ -48,11 +53,12 @@ function Component({foo, bar}) {
4853
```javascript
4954
import { c as _c } from "react/compiler-runtime"; // @inferEffectDependencies
5055
import { useEffect, useRef } from "react";
56+
import useEffectWrapper from "useEffectWrapper";
5157

5258
const moduleNonReactive = 0;
5359

5460
function Component(t0) {
55-
const $ = _c(12);
61+
const $ = _c(14);
5662
const { foo, bar } = t0;
5763

5864
const ref = useRef(0);
@@ -125,6 +131,17 @@ function Component(t0) {
125131
const f = t5;
126132

127133
useEffect(f);
134+
let t6;
135+
if ($[12] !== foo) {
136+
t6 = () => {
137+
console.log(foo);
138+
};
139+
$[12] = foo;
140+
$[13] = t6;
141+
} else {
142+
t6 = $[13];
143+
}
144+
useEffectWrapper(t6, [foo]);
128145
}
129146

130147
```

compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @inferEffectDependencies
22
import {useEffect, useRef} from 'react';
3+
import useEffectWrapper from 'useEffectWrapper';
34

45
const moduleNonReactive = 0;
56

@@ -35,4 +36,8 @@ function Component({foo, bar}) {
3536

3637
// No inferred dep array, the argument is not a lambda
3738
useEffect(f);
39+
40+
useEffectWrapper(() => {
41+
console.log(foo);
42+
});
3843
}

compiler/packages/snap/src/compiler.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,8 @@ function getEvaluatorPresets(
297297
arg.value = './shared-runtime';
298298
} else if (arg.value === 'ReactForgetFeatureFlag') {
299299
arg.value = './ReactForgetFeatureFlag';
300+
} else if (arg.value === 'useEffectWrapper') {
301+
arg.value = './useEffectWrapper';
300302
}
301303
}
302304
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
/* This file is used to test the effect auto-deps configuration, which
9+
* allows you to specify functions that should have dependencies added to
10+
* callsites.
11+
*/
12+
import {useEffect} from 'react';
13+
14+
export default function useEffectWrapper(f: () => void | (() => void)): void {
15+
useEffect(() => {
16+
f();
17+
}, [f]);
18+
}

compiler/packages/snap/src/types.d.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@
66
*/
77

88
// v0.17.1
9-
declare module "hermes-parser" {
9+
declare module 'hermes-parser' {
1010
type HermesParserOptions = {
1111
allowReturnOutsideFunction?: boolean;
1212
babel?: boolean;
13-
flow?: "all" | "detect";
13+
flow?: 'all' | 'detect';
1414
enableExperimentalComponentSyntax?: boolean;
1515
sourceFilename?: string;
16-
sourceType?: "module" | "script" | "unambiguous";
16+
sourceType?: 'module' | 'script' | 'unambiguous';
1717
tokens?: boolean;
1818
};
1919
export function parse(code: string, options: Partial<HermesParserOptions>);

0 commit comments

Comments
 (0)