Upgrade compiler playground to use the newest nextjs release, which
includes react compiler transform pipeline optimizations
https://github.com/vercel/next.js/pull/75676/.
Also made a drive-by fix to avoid the error `Cannot update a component
('Router') while rendering a different component ('StoreProvider'). To
locate the bad setState() call inside 'StoreProvider', follow the stack
trace as described in https://react.dev/link/setstate-in-render`. The
bad setState came from `history.replaceState({}, '', \`#${hash}\`);`.
Prior to this, playground ran side effects in a reducer (i.e. during
render). These have now been moved an effect.
Test fixtures testing different compiler features (e.g. non-auto
memoization) should live in separate directories.
Remove bug-prefixed fixtures that have since been fixed
Add test evaluator export to more fixtures
Prior to this PR, our HIR represented property access with numeric
literals (e.g. `myVar[0]`) as ComputedLoads. This means that they were
subject to some deopts (most notably, not being easily dedupable /
hoistable as dependencies).
Now, `PropertyLoad`, `PropertyStore`, etc reference numeric and string
literals (although not yet string literals that aren't valid babel
identifiers). The difference between PropertyLoad and ComputedLoad is
fuzzy now (maybe we should rename these).
- PropertyLoad: property keys are string and numeric literals, only when
the string literals are valid babel identifiers
- ComputedLoad: non-valid babel identifier string literals (rare) and
other non-literal expressions
The biggest feature from this PR is that it trivially enables
array-indicing expressions as dependencies. The compiler can also
specify global and imported types for arrays (e.g. return value of
`useState`)
I'm happy to close this if it complicates more than it helps --
alternative options are to entirely rely on instruction reordering-based
approaches like ReactiveGraphIR or make dependency-specific parsing +
hoisting logic more robust.
LoweredFunction dependencies were exclusively used for dependency
extraction (in `propagateScopeDeps`). Now that we have a
`propagateScopeDepsHIR` that recursively traverses into nested
functions, we can delete `dependencies` and their associated synthetic
`LoadLocal`/`PropertyLoad` instructions.
[Internal snapshot
diff](https://www.internalfb.com/phabricator/paste/view/P1716950202) for
this change shows ~.2% of files changed. I [read through ~60 of the
changed
files](https://www.internalfb.com/phabricator/paste/view/P1733074307)
- most changes are due to better outlining (due to better DCE)
- a few changes in memo inference are due to changed ordering
```
// source
arr.map(() => contextVar.inner);
// previous instructions
$0 = LoadLocal arr
$1 = $0.map
// Below instructions are synthetic
$2 = LoadLocal contextVar
$3 = $2.inner
$4 = Function deps=$3 context=contextVar {
...
}
```
- a few changes are effectively bugfixes (see
`aliased-nested-scope-fn-expr`)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/32096).
* #32099
* #32286
* #32104
* #32098
* #32097
* __->__ #32096
Adds a new Timing logger event to the compiler which currently only
records the walltime of running the compiler from the time the babel
plugin's Program visitor enters to the time it exits.
To enable, run the compiler with `ENABLE_REACT_COMPILER_TIMINGS=1 ...`
or `export ENABLE_REACT_COMPILER_TIMINGS=1` to set it by default.
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->
Improve the error message, as the value is currently an object instead
of a string, which results in it being converted to '[object Object]'.
## How did you test this change?
Already tested locally.
<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
If you leave this empty, your PR will very likely be closed.
-->
Hacky retry pipeline for when transforming `fire(...)` calls encounters
validation, todo, or memoization invariant bailouts. Would love feedback
on how we implement this to be extensible to other compiler
non-memoization features (e.g. inlineJSX)
Some observations:
- Compiler "front-end" passes (e.g. lower, type, effect, and mutability
inferences) should be shared for all compiler features -- memo and
otherwise
- Many passes (anything dealing with reactive scope ranges, scope blocks
/ dependencies, and optimizations such as ReactiveIR #31974) can be left
out of the retry pipeline. This PR hackily skips memoization features by
removing reactive scope creation, but we probably should restructure the
pipeline to skip these entirely on a retry
- We should maintain a canonical set of "validation flags"
Note the newly added fixtures are prefixed with `bailout-...` when the
retry fire pipeline is used. These fixture outputs contain correctly
inserted `useFire` calls and no memoization.
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
Contributing to https://github.com/facebook/react/pull/32240, this
change adds the dev dependencies needed to support the migration of the
plugin to typescript.
## Summary
PR https://github.com/facebook/react/pull/31963 migrated the bundler
from Rollup to esbuild, but the `react-compiler-healthcheck` script
lacks a shebang, leading to issues with `npx` not being able to execute
it.
dc7578290f/compiler/packages/react-compiler-healthcheck/rollup.config.js (L60-L78)9eabb37338/compiler/packages/react-compiler-healthcheck/scripts/build.js (L38-L53)
## How did you test this change?
**Before**
(fail)
```shell
(main)> npx --version
10.5.0
(main)> npx react-compiler-healthcheck
/home/jeremy/.npm/_npx/67b118a83a29962c/node_modules/.bin/react-compiler-healthcheck: line 1: /bin: Is a directory
/home/jeremy/.npm/_npx/67b118a83a29962c/node_modules/.bin/react-compiler-healthcheck: line 2: syntax error near unexpected token `('
/home/jeremy/.npm/_npx/67b118a83a29962c/node_modules/.bin/react-compiler-healthcheck: line 2: ` * Copyright (c) Meta Platforms, Inc. and affiliates.'
```
**After**
```shell
(main)> npx react-compiler-healthcheck
Successfully compiled 108 out of 146 components.
StrictMode usage not found.
Found no usage of incompatible libraries.
```
I wrote this a couple summers back as an experiment to see how easily we could translate the compiler to Rust. We make extensive use of in-place mutation of the IR, and the experiment proved that this we can get reasonable ergonomics for this in Rust which was cool. We've since ended up using some of the code here for Relay, allowing Relay Compiler to parse JS files to do more fine-grained extraction of data. For React Compiler though, we plan to continue using JavaScript and explore lightweight native wrappers for things like OXC and SWC plugins. We're also working with the Hermes team to eventually compile the compiler with Static Hermes.
As Tomo always says: always bet on JavaScript.
ghstack-source-id: c5770a2efc
Pull Request resolved: https://github.com/facebook/react/pull/32219
<!--
Thanks for submitting a pull request!
We appreciate you spending the time to work on these changes. Please
provide enough information so that others can review your pull request.
The three fields below are mandatory.
Before submitting a pull request, please make sure the following is
done:
1. Fork [the repository](https://github.com/facebook/react) and create
your branch from `main`.
2. Run `yarn` in the repository root.
3. If you've fixed a bug or added code that should be tested, add tests!
4. Ensure the test suite passes (`yarn test`). Tip: `yarn test --watch
TestName` is helpful in development.
5. Run `yarn test --prod` to test in the production environment. It
supports the same options as `yarn test`.
6. If you need a debugger, run `yarn test --debug --watch TestName`,
open `chrome://inspect`, and press "Inspect".
7. Format your code with
[prettier](https://github.com/prettier/prettier) (`yarn prettier`).
8. Make sure your code lints (`yarn lint`). Tip: `yarn linc` to only
check changed files.
9. Run the [Flow](https://flowtype.org/) type checks (`yarn flow`).
10. If you haven't already, complete the CLA.
Learn more about contributing:
https://reactjs.org/docs/how-to-contribute.html
-->
## Summary
Our [LlamaIndex](https://www.llamaindex.ai/) Product is blocked by this
bug
Fixes: https://github.com/facebook/react/issues/32137
<!--
Explain the **motivation** for making this change. What existing problem
does the pull request solve?
-->
## How did you test this change?
<!--
Demonstrate the code is solid. Example: The exact commands you ran and
their output, screenshots / videos if the pull request changes the user
interface.
How exactly did you verify that your PR solves the issue you wanted to
solve?
If you leave this empty, your PR will very likely be closed.
-->
For now we just reject all calls of impure functions, and the validation
is off by default. Going forward we can make this more precise and only
reject impure functions called during render.
Note that I was intentionally imprecise in the return type of these
functions in order to avoid changing output of existing code. We lie to
the compiler and say that Date.now, performance.now, and Math.random
return unknown mutable objects rather than primitives. Once the
validation is complete and vetted we can switch this to be more precise.
Alternative to #32071. As a follow up to #31993, the `platform` target
was incorrectly being set to `browser` since it was the default argument
for the build script. This corrects it to `node` and `cjs` which I think
should resolve node 20 issues.
## Summary
This change fixes a gap in the plugin's support of eslint v9. In one
place that it's using the `SourceCode` api, it's correctly considering
v9's api. But in the other place where `SourceCode` is used, it's only
using the legacy api, which was removed in v9.
- Adds @compilationMode(all|infer|syntax|annotation) and
@panicMode(none) directives. This is now shared with our test infra
- Playground still defaults to `infer` mode while tests default to `all`
mode
- See added fixture tests
I had forgotten that our default error reporting threshold was `none`
due to the fact that build pipelines should not throw errors. This
resets it back to throwing on all errors which mostly is the same as the
eslint plugin.
Closes#32014.
The playground's compilation mode is currently set to 'all' along with
reporting all errors.
This tends to be misleading since people usually expect a 1:1 match
between how the playground works with what the compiler does in their
codebase, eg https://github.com/reactwg/react-compiler/discussions/51.
This migrates the compiler's bundler to esbuild instead of rollup.
Unlike React, our bundling use cases are far simpler since the majority
of our packages are meant to be run on node. Rollup was adding
considerable build time overhead whereas esbuild remains fast and has
all the functionality we need out of the box.
### Before
```
time yarn workspaces run build
yarn workspaces v1.22.22
> babel-plugin-react-compiler
yarn run v1.22.22
$ rimraf dist && rollup --config --bundleConfigAsCjs
src/index.ts → dist/index.js...
(!) Circular dependencies
# ...
created dist/index.js in 15.5s
✨ Done in 16.45s.
> eslint-plugin-react-compiler
yarn run v1.22.22
$ rimraf dist && rollup --config --bundleConfigAsCjs
src/index.ts → dist/index.js...
(!) Circular dependencies
# ...
created dist/index.js in 9.1s
✨ Done in 10.11s.
> make-read-only-util
yarn run v1.22.22
warning package.json: No license field
$ tsc
✨ Done in 1.81s.
> react-compiler-healthcheck
yarn run v1.22.22
$ rimraf dist && rollup --config --bundleConfigAsCjs
src/index.ts → dist/index.js...
(!) Circular dependencies
# ...
created dist/index.js in 8.7s
✨ Done in 10.43s.
> react-compiler-runtime
yarn run v1.22.22
$ rimraf dist && rollup --config --bundleConfigAsCjs
src/index.ts → dist/index.js...
(!) src/index.ts (1:0): Module level directives cause errors when bundled, "use no memo" in "src/index.ts" was ignored.
# ...
created dist/index.js in 1.1s
✨ Done in 1.82s.
> snap
yarn run v1.22.22
$ rimraf dist && concurrently -n snap,runtime "tsc --build" "yarn --silent workspace react-compiler-runtime build --silent"
$ rimraf dist && rollup --config --bundleConfigAsCjs --silent
[runtime] yarn --silent workspace react-compiler-runtime build --silent exited with code 0
[snap] tsc --build exited with code 0
✨ Done in 5.73s.
✨ Done in 47.30s.
yarn workspaces run build 75.92s user 5.48s system 170% cpu 47.821 total
```
### After
```
time yarn workspaces run build
yarn workspaces v1.22.22
> babel-plugin-react-compiler
yarn run v1.22.22
$ rimraf dist && scripts/build.js
✨ Done in 1.02s.
> eslint-plugin-react-compiler
yarn run v1.22.22
$ rimraf dist && scripts/build.js
✨ Done in 0.93s.
> make-read-only-util
yarn run v1.22.22
warning package.json: No license field
$ rimraf dist && scripts/build.js
✨ Done in 0.89s.
> react-compiler-healthcheck
yarn run v1.22.22
$ rimraf dist && scripts/build.js
✨ Done in 0.58s.
> react-compiler-runtime
yarn run v1.22.22
$ rimraf dist && scripts/build.js
✨ Done in 0.48s.
> snap
yarn run v1.22.22
$ rimraf dist && concurrently -n snap,runtime "tsc --build" "yarn --silent workspace react-compiler-runtime build"
$ rimraf dist && scripts/build.js
[runtime] yarn --silent workspace react-compiler-runtime build exited with code 0
[snap] tsc --build exited with code 0
✨ Done in 4.69s.
✨ Done in 9.46s.
yarn workspaces run build 9.70s user 0.99s system 103% cpu 10.329 total
```
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31963).
* #31964
* __->__ #31963
* #31962
Traverse the compiled functions to ensure there are no lingering fires
and that all
fire calls are inside an effect lambda.
Also corrects the import to import from the compiler runtime instead
--
This is the diff with the meaningful changes. The approach is:
1. Collect fire callees and remove fire() calls, create a new binding
for the useFire result
2. Update LoadLocals for captured callees to point to the useFire result
3. Update function context to reference useFire results
4. Insert useFire calls after getting to the component scope
This approach aims to minimize the amount of new bindings we introduce
for the function expressions
to minimize bookkeeping for dependency arrays. We keep all of the
LoadLocals leading up to function
calls as they are and insert new instructions to load the originally
captured function, call useFire,
and store the result in a new promoted temporary. The lvalues that
referenced the original callee are
changed to point to the new useFire result.
This is the minimal diff to implement the expected behavior (up to
importing the useFire call, next diff)
and further stacked diffs implement error handling. The rules for fire
are:
1. If you use fire for a callee in the effect once you must use it for
every time you call it in that effect
2. You can only use fire in a useEffect lambda/functions defined inside
the useEffect lambda
There is still more work to do here, like updating the effect dependency
array and handling object methods
--
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/31796).
* #31811
* #31798
* #31797
* __->__ #31796
We report a false positive for the combination of a ref-accessing
function placed inside an array which is they type-cast. Here we teach
ref validation about type casts. I also tried other variants like
`return ref as const` but those already worked.
Closes#31864