Skip to content

Commit

Permalink
[compiler] Support default imports for autodep config (facebook#31657)
Browse files Browse the repository at this point in the history
## 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
  • Loading branch information
jbrown215 authored Dec 3, 2024
1 parent 2ab471c commit 1b1283a
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,13 @@ const testComplexConfigDefaults: PartialEnvironmentConfig = {
},
numRequiredArgs: 2,
},
{
function: {
source: 'useEffectWrapper',
importSpecifierName: 'default',
},
numRequiredArgs: 1,
},
],
};

Expand Down Expand Up @@ -1147,3 +1154,5 @@ export function tryParseExternalFunction(
suggestions: null,
});
}

export const DEFAULT_EXPORT = 'default';
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
Place,
ReactiveScopeDependencies,
} from '../HIR';
import {DEFAULT_EXPORT} from '../HIR/Environment';
import {
createTemporaryPlace,
fixScopeAndIdentifierRanges,
Expand Down Expand Up @@ -97,6 +98,17 @@ export function inferEffectDependencies(fn: HIRFunction): void {
autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
}
}
} else if (
value.kind === 'LoadGlobal' &&
value.binding.kind === 'ImportDefault'
) {
const moduleTargets = autodepFnConfigs.get(value.binding.module);
if (moduleTargets != null) {
const numRequiredArgs = moduleTargets.get(DEFAULT_EXPORT);
if (numRequiredArgs != null) {
autodepFnLoads.set(lvalue.identifier.id, numRequiredArgs);
}
}
} else if (
/*
* TODO: Handle method calls
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
```javascript
// @inferEffectDependencies
import {useEffect, useRef} from 'react';
import useEffectWrapper from 'useEffectWrapper';

const moduleNonReactive = 0;

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

// No inferred dep array, the argument is not a lambda
useEffect(f);

useEffectWrapper(() => {
console.log(foo);
});
}

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

const moduleNonReactive = 0;

function Component(t0) {
const $ = _c(12);
const $ = _c(14);
const { foo, bar } = t0;

const ref = useRef(0);
Expand Down Expand Up @@ -125,6 +131,17 @@ function Component(t0) {
const f = t5;

useEffect(f);
let t6;
if ($[12] !== foo) {
t6 = () => {
console.log(foo);
};
$[12] = foo;
$[13] = t6;
} else {
t6 = $[13];
}
useEffectWrapper(t6, [foo]);
}

```
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @inferEffectDependencies
import {useEffect, useRef} from 'react';
import useEffectWrapper from 'useEffectWrapper';

const moduleNonReactive = 0;

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

// No inferred dep array, the argument is not a lambda
useEffect(f);

useEffectWrapper(() => {
console.log(foo);
});
}
2 changes: 2 additions & 0 deletions compiler/packages/snap/src/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ function getEvaluatorPresets(
arg.value = './shared-runtime';
} else if (arg.value === 'ReactForgetFeatureFlag') {
arg.value = './ReactForgetFeatureFlag';
} else if (arg.value === 'useEffectWrapper') {
arg.value = './useEffectWrapper';
}
}
}
Expand Down
18 changes: 18 additions & 0 deletions compiler/packages/snap/src/sprout/useEffectWrapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/* This file is used to test the effect auto-deps configuration, which
* allows you to specify functions that should have dependencies added to
* callsites.
*/
import {useEffect} from 'react';

export default function useEffectWrapper(f: () => void | (() => void)): void {
useEffect(() => {
f();
}, [f]);
}
6 changes: 3 additions & 3 deletions compiler/packages/snap/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
*/

// v0.17.1
declare module "hermes-parser" {
declare module 'hermes-parser' {
type HermesParserOptions = {
allowReturnOutsideFunction?: boolean;
babel?: boolean;
flow?: "all" | "detect";
flow?: 'all' | 'detect';
enableExperimentalComponentSyntax?: boolean;
sourceFilename?: string;
sourceType?: "module" | "script" | "unambiguous";
sourceType?: 'module' | 'script' | 'unambiguous';
tokens?: boolean;
};
export function parse(code: string, options: Partial<HermesParserOptions>);
Expand Down

0 comments on commit 1b1283a

Please sign in to comment.