Skip to content

[compiler][gating] Experimental directive based gating #33149

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

Merged
merged 2 commits into from
May 21, 2025
Merged

[compiler][gating] Experimental directive based gating #33149

merged 2 commits into from
May 21, 2025

Conversation

mofeiZ
Copy link
Contributor

@mofeiZ mofeiZ commented May 7, 2025

Adds dynamicGating as an experimental option for testing rollout DX at Meta. If specified, this enables dynamic gating which matches use memo if(...) directives.

Example usage

Input file

// @dynamicGating:{"source":"myModule"}
export function MyComponent() {
  'use memo if(isEnabled)';
   return <div>...</div>;
}

Compiler output

import {isEnabled} from 'myModule';
export const MyComponent = isEnabled()
  ? <optimized version>
  : <original version>;

Stack created with Sapling. Best reviewed with ReviewStack.

Copy link
Member

@josephsavona josephsavona left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would this work for real code? If you use the use memo if(...) form, what would we use as the source of the import?

@mofeiZ
Copy link
Contributor Author

mofeiZ commented May 8, 2025

How would this work for real code? If you use the use memo if(...) form, what would we use as the source of the import?

For a large codebase internally, we added a react-compiler-gating-for-<project>.js file which:

  • is unconditionally added to our bundles (imported at the same resource tier as React)
  • exports gating functions e.g. function enabledForSubproject() {...}

This codebase currently uses a lightweight wrapper around the gating config, but we can extend the same self-service gating function mechanism to use memo if(...) rollouts.

We briefly discussed inserting more analyzable gating (e.g. is_feature_flag_enabled('feature_flag_name')) calls which can be understood by other babel transforms, but decided that the additional complexity is not worth it for now.

Letting developers specify their own filenames (e.g. use memo if(myModuleName)) would also be a pain, as we would need to have some way of ensuring the specified module is included in relevant bundles.

@mofeiZ mofeiZ force-pushed the pr33149 branch 2 times, most recently from 672e66b to 4c48a87 Compare May 8, 2025 16:41
Comment on lines +56 to +61
const dynamicGating = findDirectivesDynamicGating(directives, opts);
if (dynamicGating.isOk()) {
return Ok(dynamicGating.unwrap()?.directive ?? null);
} else {
return Err(dynamicGating.unwrapErr());
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dynamic gating should also be an opt-in if compilationMode: "annotation" is enabled.

If "use no memo" is set at module scope, use memo if(...) should have the same semantics as use memo, whatever that is

}
const functionGating = dynamicGating ?? pass.opts.gating;
if (kind === 'original' && functionGating != null) {
referencedBeforeDeclared ??=
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure how we feel about ??= when the right hand side is a potentially expensive computation. I'm happy to make this more explicit if that's preferred (e.g. if (referencedBeforeDeclared == null) ...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this is fine, ??= is a short-circuiting operator just like ||=

@mofeiZ mofeiZ force-pushed the pr33149 branch 5 times, most recently from 0013ccc to 5b7cdf7 Compare May 8, 2025 20:39
@mofeiZ mofeiZ marked this pull request as ready for review May 8, 2025 20:40
Copy link
Member

@josephsavona josephsavona left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice!

}
const functionGating = dynamicGating ?? pass.opts.gating;
if (kind === 'original' && functionGating != null) {
referencedBeforeDeclared ??=
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this is fine, ??= is a short-circuiting operator just like ||=

mofeiZ added a commit that referenced this pull request May 9, 2025
React Compiler's program traversal logic is pretty lengthy and complex
as we've added a lot of features piecemeal. `compileProgram` is 300+
lines long and has confusing control flow (defining helpers inline,
invoking visitors, mutating-asts-while-iterating, mutating global
`ALREADY_COMPILED` state).

- Moved more stuff to `ProgramContext`
- Separated `compileProgram` into a bunch of helpers

Tested by syncing this stack to a Meta codebase and observing no
compilation output changes (D74487851, P1806855669, P1806855379)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33147).
* #33149
* #33148
* __->__ #33147
github-actions bot pushed a commit that referenced this pull request May 9, 2025
React Compiler's program traversal logic is pretty lengthy and complex
as we've added a lot of features piecemeal. `compileProgram` is 300+
lines long and has confusing control flow (defining helpers inline,
invoking visitors, mutating-asts-while-iterating, mutating global
`ALREADY_COMPILED` state).

- Moved more stuff to `ProgramContext`
- Separated `compileProgram` into a bunch of helpers

Tested by syncing this stack to a Meta codebase and observing no
compilation output changes (D74487851, P1806855669, P1806855379)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33147).
* #33149
* #33148
* __->__ #33147

DiffTrain build for [5069e18](5069e18)
github-actions bot pushed a commit that referenced this pull request May 9, 2025
React Compiler's program traversal logic is pretty lengthy and complex
as we've added a lot of features piecemeal. `compileProgram` is 300+
lines long and has confusing control flow (defining helpers inline,
invoking visitors, mutating-asts-while-iterating, mutating global
`ALREADY_COMPILED` state).

- Moved more stuff to `ProgramContext`
- Separated `compileProgram` into a bunch of helpers

Tested by syncing this stack to a Meta codebase and observing no
compilation output changes (D74487851, P1806855669, P1806855379)
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33147).
* #33149
* #33148
* __->__ #33147

DiffTrain build for [5069e18](5069e18)
mofeiZ added 2 commits May 9, 2025 13:30
Adds `dynamicGating` as an experimental option for testing rollout DX at Meta. If specified, this enables dynamic gating which matches `use memo if(...)` directives.

#### Example usage
Input file
```js
// @dynamicGating:{"source":"myModule"}
export function MyComponent() {
  'use memo if(isEnabled)';
   return <div>...</div>;
}
```
Compiler output
```js
import {isEnabled} from 'myModule';
export const MyComponent = isEnabled()
  ? <optimized version>
  : <original version>;
```
mofeiZ added a commit that referenced this pull request May 9, 2025
Title
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33148).
* #33149
* __->__ #33148
github-actions bot pushed a commit that referenced this pull request May 9, 2025
Title
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33148).
* #33149
* __->__ #33148

DiffTrain build for [3820740](3820740)
github-actions bot pushed a commit that referenced this pull request May 9, 2025
Title
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33148).
* #33149
* __->__ #33148

DiffTrain build for [3820740](3820740)
github-actions bot pushed a commit to code/lib-react that referenced this pull request May 9, 2025
…k#33148)

Title
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33148).
* facebook#33149
* __->__ facebook#33148

DiffTrain build for [3820740](facebook@3820740)
github-actions bot pushed a commit to nikeee/react that referenced this pull request May 9, 2025
…k#33148)

Title
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33148).
* facebook#33149
* __->__ facebook#33148

DiffTrain build for [3820740](facebook@3820740)
github-actions bot pushed a commit to code/lib-react that referenced this pull request May 9, 2025
…k#33148)

Title
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33148).
* facebook#33149
* __->__ facebook#33148

DiffTrain build for [3820740](facebook@3820740)
github-actions bot pushed a commit to nikeee/react that referenced this pull request May 9, 2025
…k#33148)

Title
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33148).
* facebook#33149
* __->__ facebook#33148

DiffTrain build for [3820740](facebook@3820740)
@mofeiZ mofeiZ merged commit 459a2c4 into main May 21, 2025
4 checks passed
github-actions bot pushed a commit that referenced this pull request May 21, 2025
Adds `dynamicGating` as an experimental option for testing rollout DX at
Meta. If specified, this enables dynamic gating which matches `use memo
if(...)` directives.

#### Example usage
Input file
```js
// @dynamicGating:{"source":"myModule"}
export function MyComponent() {
  'use memo if(isEnabled)';
   return <div>...</div>;
}
```
Compiler output
```js
import {isEnabled} from 'myModule';
export const MyComponent = isEnabled()
  ? <optimized version>
  : <original version>;
```
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33149).
* __->__ #33149
* #33148

DiffTrain build for [459a2c4](459a2c4)
github-actions bot pushed a commit that referenced this pull request May 21, 2025
Adds `dynamicGating` as an experimental option for testing rollout DX at
Meta. If specified, this enables dynamic gating which matches `use memo
if(...)` directives.

#### Example usage
Input file
```js
// @dynamicGating:{"source":"myModule"}
export function MyComponent() {
  'use memo if(isEnabled)';
   return <div>...</div>;
}
```
Compiler output
```js
import {isEnabled} from 'myModule';
export const MyComponent = isEnabled()
  ? <optimized version>
  : <original version>;
```
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33149).
* __->__ #33149
* #33148

DiffTrain build for [459a2c4](459a2c4)
github-actions bot pushed a commit to code/lib-react that referenced this pull request May 22, 2025
Adds `dynamicGating` as an experimental option for testing rollout DX at
Meta. If specified, this enables dynamic gating which matches `use memo
if(...)` directives.

#### Example usage
Input file
```js
// @dynamicGating:{"source":"myModule"}
export function MyComponent() {
  'use memo if(isEnabled)';
   return <div>...</div>;
}
```
Compiler output
```js
import {isEnabled} from 'myModule';
export const MyComponent = isEnabled()
  ? <optimized version>
  : <original version>;
```
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33149).
* __->__ facebook#33149
* facebook#33148

DiffTrain build for [459a2c4](facebook@459a2c4)
github-actions bot pushed a commit to code/lib-react that referenced this pull request May 22, 2025
Adds `dynamicGating` as an experimental option for testing rollout DX at
Meta. If specified, this enables dynamic gating which matches `use memo
if(...)` directives.

#### Example usage
Input file
```js
// @dynamicGating:{"source":"myModule"}
export function MyComponent() {
  'use memo if(isEnabled)';
   return <div>...</div>;
}
```
Compiler output
```js
import {isEnabled} from 'myModule';
export const MyComponent = isEnabled()
  ? <optimized version>
  : <original version>;
```
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/facebook/react/pull/33149).
* __->__ facebook#33149
* facebook#33148

DiffTrain build for [459a2c4](facebook@459a2c4)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants