react/compiler
mofeiZ 9d795d3808
[compiler][bugfix] expand StoreContext to const / let / function variants (#32747)
```js
function Component() {
  useEffect(() => {
    let hasCleanedUp = false;
    document.addEventListener(..., () => hasCleanedUp ? foo() : bar());
    // effect return values shouldn't be typed as frozen
    return () => {
      hasCleanedUp = true;
    }
  };
}
```
### Problem
`PruneHoistedContexts` currently strips hoisted declarations and
rewrites the first `StoreContext` reassignment to a declaration. For
example, in the following example, instruction 0 is removed while a
synthetic `DeclareContext let` is inserted before instruction 1.

```js
// source
const cb = () => x; // reference that causes x to be hoisted

let x = 4;
x = 5;

// React Compiler IR
[0] DeclareContext HoistedLet 'x'
...
[1] StoreContext reassign 'x' = 4
[2] StoreContext reassign 'x' = 5
```

Currently, we don't account for `DeclareContext let`. As a result, we're
rewriting to insert duplicate declarations.
```js
// source
const cb = () => x; // reference that causes x to be hoisted

let x;
x = 5;

// React Compiler IR
[0] DeclareContext HoistedLet 'x'
...
[1] DeclareContext Let 'x'
[2] StoreContext reassign 'x' = 5
```

### Solution

Instead of always lowering context variables to a DeclareContext
followed by a StoreContext reassign, we can keep `kind: 'Const' | 'Let'
| 'Reassign' | etc` on StoreContext.
Pros:
- retain more information in HIR, so we can codegen easily `const` and
`let` context variable declarations back
- pruning hoisted `DeclareContext` instructions is simple.

Cons:
- passes are more verbose as we need to check for both `DeclareContext`
and `StoreContext` declarations

~(note: also see alternative implementation in
https://github.com/facebook/react/pull/32745)~

### Testing
Context variables are tricky. I synced and diffed changes in a large
meta codebase and feel pretty confident about landing this. About 0.01%
of compiled files changed. Among these changes, ~25% were [direct
bugfixes](https://www.internalfb.com/phabricator/paste/view/P1800029094).
The [other
changes](https://www.internalfb.com/phabricator/paste/view/P1800028575)
were primarily due to changed (corrected) mutable ranges from
https://github.com/facebook/react/pull/33047. I tried to represent most
interesting changes in new test fixtures

`
2025-04-30 17:18:58 -04:00
..
apps/playground [chore] Update caniuse-lite (#33013) 2025-04-24 13:50:03 -04:00
docs Update DEVELOPMENT_GUIDE.md (#32281) 2025-03-13 11:45:26 -04:00
fixtures [cleanup] Remove compiler runtime-compat fixture library (#31430) 2024-11-05 14:14:39 -05:00
packages [compiler][bugfix] expand StoreContext to const / let / function variants (#32747) 2025-04-30 17:18:58 -04:00
scripts [compiler] Add missing copyrights (#33004) 2025-04-23 22:04:44 -04:00
.eslintrc.js [compiler:codegen] Wrap non-ascii characters in JsxExpressionContainer 2024-06-21 10:08:15 -04:00
.gitignore [forgive] Init (#31918) 2025-02-25 12:19:11 -05:00
CHANGELOG.md [compiler] Add changelog (#32983) 2025-04-24 16:20:02 -04:00
package.json [compiler] Update rimraf (#32868) 2025-04-14 15:15:14 -04:00
README.md Update readme and other docs 2024-05-06 14:53:47 -07:00
yarn.lock [mdn] Initial experiment for adding performance tool (#33045) 2025-04-30 12:44:05 -07:00

React Compiler

React Compiler is a compiler that optimizes React applications, ensuring that only the minimal parts of components and hooks will re-render when state changes. The compiler also validates that components and hooks follow the Rules of React.

More information about the design and architecture of the compiler are covered in the Design Goals.

More information about developing the compiler itself is covered in the Development Guide.