diff --git a/compiler/packages/babel-plugin-react-forget/src/HIR/Environment.ts b/compiler/packages/babel-plugin-react-forget/src/HIR/Environment.ts index b7eacef613..471d089ad9 100644 --- a/compiler/packages/babel-plugin-react-forget/src/HIR/Environment.ts +++ b/compiler/packages/babel-plugin-react-forget/src/HIR/Environment.ts @@ -210,6 +210,26 @@ export type EnvironmentConfig = { * https://github.com/babel/babel/pull/10917/files#diff-19b555d2f3904c206af406540d9df200b1e16befedb83ff39ebfcbd876f7fa8aL52-R56 */ bailoutOnHoleyArrays: boolean; + + /** + * Enable emitting "change variables" which store the result of whether a particular + * reactive scope dependency has changed since the scope was last executed. + * + * Ex: + * ``` + * const c_0 = $[0] !== input; // change variable + * let output; + * if (c_0) ... + * ``` + * + * Defaults to false, where the comparison is inlined: + * + * ``` + * let output; + * if ($[0] !== input) ... + * ``` + */ + enableChangeVariableCodegen: boolean; }; export const DEFAULT_ENVIRONMENT_CONFIG: Readonly = { @@ -225,6 +245,7 @@ export const DEFAULT_ENVIRONMENT_CONFIG: Readonly = { enableAssumeHooksFollowRulesOfReact: false, enableEmitFreeze: null, enableForest: false, + enableChangeVariableCodegen: false, validateFrozenLambdas: false, validateNoSetStateInRender: false, diff --git a/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts b/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts index 8a65ea14bc..9657d0a28b 100644 --- a/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts +++ b/compiler/packages/babel-plugin-react-forget/src/ReactiveScopes/CodegenReactiveFunction.ts @@ -241,14 +241,23 @@ function codegenMemoBlockForReactiveScope( for (const dep of scope.dependencies) { const index = cx.nextCacheIndex; const depValue = codegenDependency(cx, dep); - - changeExpressions.push( - t.binaryExpression( - "!==", - t.memberExpression(t.identifier("$"), t.numericLiteral(index), true), - depValue - ) + const comparison = t.binaryExpression( + "!==", + t.memberExpression(t.identifier("$"), t.numericLiteral(index), true), + depValue ); + + if (cx.env.config.enableChangeVariableCodegen) { + const changeIdentifier = t.identifier(`c_${index}`); + statements.push( + t.variableDeclaration("const", [ + t.variableDeclarator(changeIdentifier, comparison), + ]) + ); + changeExpressions.push(changeIdentifier); + } else { + changeExpressions.push(comparison); + } cacheStoreStatements.push( t.expressionStatement( t.assignmentExpression( diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/option-enable-change-variable-codegen.expect.md b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/option-enable-change-variable-codegen.expect.md new file mode 100644 index 0000000000..79a0686014 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/option-enable-change-variable-codegen.expect.md @@ -0,0 +1,45 @@ + +## Input + +```javascript +// @enableChangeVariableCodegen +function Component(props) { + const x = [props.a, props.b.c]; + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ a: 3.14, b: { c: true } }], +}; + +``` + +## Code + +```javascript +import { unstable_useMemoCache as useMemoCache } from "react"; // @enableChangeVariableCodegen +function Component(props) { + const $ = useMemoCache(3); + const c_0 = $[0] !== props.a; + const c_1 = $[1] !== props.b.c; + let t0; + if (c_0 || c_1) { + t0 = [props.a, props.b.c]; + $[0] = props.a; + $[1] = props.b.c; + $[2] = t0; + } else { + t0 = $[2]; + } + const x = t0; + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ a: 3.14, b: { c: true } }], +}; + +``` + \ No newline at end of file diff --git a/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/option-enable-change-variable-codegen.js b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/option-enable-change-variable-codegen.js new file mode 100644 index 0000000000..e316c1db92 --- /dev/null +++ b/compiler/packages/babel-plugin-react-forget/src/__tests__/fixtures/compiler/option-enable-change-variable-codegen.js @@ -0,0 +1,10 @@ +// @enableChangeVariableCodegen +function Component(props) { + const x = [props.a, props.b.c]; + return x; +} + +export const FIXTURE_ENTRYPOINT = { + fn: Component, + params: [{ a: 3.14, b: { c: true } }], +};