-
Notifications
You must be signed in to change notification settings - Fork 47.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[compiler] detect and throw on untransformed required features #32512
base: main
Are you sure you want to change the base?
Conversation
4 | function nonReactFn(arg) { | ||
> 5 | useEffect(() => [1, 2, arg]); | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Todo: Untransformed reference to experimental compiler-only feature (5:5) | ||
6 | } | ||
7 | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Erroring on an untransformed call anywhere within the program is intentional, as we expect untransformed calls to be invalid / throw at runtime.
> 20 | useEffect(f); | ||
| ^^^^^^^^^^^^ Todo: Untransformed reference to experimental compiler-only feature (20:20) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here -- this error is intentional as we expect untransformed calls to be invalid / throw at runtime.
## Input | ||
|
||
```javascript | ||
// @inferEffectDependencies @compilationMode(infer) @panicThreshold(none) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that these fixtures error even with @panicThreshold(none)
. This PR changes inferEffectDeps
to be a "required" feature (e.g. if enabled, relevant code must either be transformed or fail compilation)
Removes `EnvironmentConfig.enableMinimalTransformsForRetry` in favor of `run` parameters. This is a minimal difference but lets us explicitly opt out certain compiler passes based on mode parameters, instead of environment configurations Retry flags don't really make sense to have in `EnvironmentConfig` anyways as the config is user-facing API, while retrying is a compiler implementation detail. (per @josephsavona's feedback #32164 (comment)) > Re the "hacky" framing of this in the PR title: I think this is fine. I can see having something like a compilation or output mode that we use when running the pipeline. Rather than changing environment settings when we re-run, various passes could take effect based on the combination of the mode + env flags. The modes might be: > > * Full: transform, validate, memoize. This is the default today. > * Transform: Along the lines of the backup mode in this PR. Only applies transforms that do not require following the rules of React, like `fire()`. > * Validate: This could be used for ESLint.
logError(err, pass, fn.node.loc ?? null); | ||
throw err; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't quite right -- we want
- only retry compilation if fire or effect dependencies might be called
- stash or return this error to later throw (in
ValidateNoUntransformed
)
Traverse program after running compiler transform to find untransformed references to compiler features (e.g. `inferEffectDeps`, `fire`). Hard error to fail the babel pipeline when the compiler fails to transform these features to give predictable runtime semantics. Untransformed calls to functions like `fire` will throw at runtime anyways, so let's fail the build to catch these earlier. Note that with this fails the build *regardless of panicThreshold* This PR also throws retry pipeline errors, which shows better errors than the current generic TODO message
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Behaviors look good to me! We'll definitely need more actionable error messages so that people can figure out how to make the build errors go away, but this is an excellent start. Left some clarifying questions inline.
} | ||
|
||
// No inferred dep array, the argument is not a lambda | ||
useEffect(f); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are useEffect wrappers that forward a function + dep array that will block us from enabling this rule, e.g.:
function useMyEffect(fn, deps) {
useEffect(fn, deps);
// ... other stuff
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should allow non-lambda arguments so long as a dep array is provided, I think?
|
||
/** | ||
* Note that a react compiler-based transform still has limitations on JS syntax. | ||
* We should surface these as actionable lint / build errors to devs. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The fix here is to specify the dep array (for special effect, that's a second dep array), is that right?
import {useEffect} from 'react'; | ||
|
||
function Component({propVal}) { | ||
'use no memo'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this mean 'use no memo'
should not disable autodeps/fire? (that sounds right to me, just checking if that's your intent)
function useFoo({cond}) { | ||
const ref = useRef(); | ||
const derived = cond ? ref.current : makeObject(); | ||
useSpecialEffect(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, we currently depend on memoization? I thought we only depended on reactivity analysis
Traverse program after running compiler transform to find untransformed references to compiler features (e.g.
inferEffectDeps
,fire
).Hard error to fail the babel pipeline when the compiler fails to transform these features to give predictable runtime semantics. Untransformed calls to functions like
fire
will throw at runtime anyways, so let's fail the build to catch these earlier.Note that with this fails the build regardless of panicThreshold
This PR also throws retry pipeline errors, which shows better errors than the current generic TODO message
Stack created with Sapling. Best reviewed with ReviewStack.
fireRetry
flag -> compileMode #32511