[compiler] Deprecate noEmit, add outputMode (#35112)
This deprecates the `noEmit: boolean` flag and adds `outputMode: 'client' | 'client-no-memo' | 'ssr' | 'lint'` as the replacement. OutputMode defaults to null and takes precedence if specified, otherwise we use 'client' mode for noEmit=false and 'lint' mode for noEmit=true. Key points: * Retrying failed compilation switches from 'client' mode to 'client-no-memo' * Validations are enabled behind Environment.proto.shouldEnableValidations, enabled for all modes except 'client-no-memo'. Similar for dropping manual memoization. * OptimizeSSR is now gated by the outputMode==='ssr', not a feature flag * Creation of reactive scopes, and related codegen logic, is now gated by outputMode==='client'
Joseph Savona committed
Nov 20, 2025 at 15:12 UTC
50e7ec8a694072fd6fcd52182df8a75211bf084d
30 files changed
+514
-216
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Options.ts
+26
-1
@@ -102,14 +102,25 @@ export type PluginOptions = Partial<{
102
103
panicThreshold: PanicThresholdOptions;
104
105
- /*
105
+ /**
106
+ * @deprecated
107
+ *
108
* When enabled, Forget will continue statically analyzing and linting code, but skip over codegen
109
* passes.
110
*
111
+ * NOTE: ignored if `outputMode` is specified
112
+ *
113
* Defaults to false
114
*/
115
noEmit: boolean;
116
117
+ /**
118
+ * If specified, overrides `noEmit` and controls the output mode of the compiler.
119
+ *
120
+ * Defaults to null
121
+ */
122
+ outputMode: CompilerOutputMode | null;
123
+
124
/*
125
* Determines the strategy for determining which functions to compile. Note that regardless of
126
* which mode is enabled, a component can be opted out by adding the string literal
@@ -212,6 +223,19 @@ const CompilationModeSchema = z.enum([
223
224
export type CompilationMode = z.infer<typeof CompilationModeSchema>;
225
226
+const CompilerOutputModeSchema = z.enum([
227
+ // Build optimized for SSR, with client features removed
228
+ 'ssr',
229
+ // Build optimized for the client, with auto memoization
230
+ 'client',
231
+ // Build optimized for the client without auto memo
232
+ 'client-no-memo',
233
+ // Lint mode, the output is unused but validations should run
234
+ 'lint',
235
+]);
236
+
237
+export type CompilerOutputMode = z.infer<typeof CompilerOutputModeSchema>;
238
+
239
/**
240
* Represents 'events' that may occur during compilation. Events are only
241
* recorded when a logger is set (through the config).
@@ -293,6 +317,7 @@ export const defaultOptions: ParsedPluginOptions = {
317
logger: null,
318
gating: null,
319
noEmit: false,
320
+ outputMode: null,
321
dynamicGating: null,
322
eslintSuppressionRules: null,
323
flowSuppressions: true,
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Pipeline.ts
+15
-18
@@ -8,7 +8,7 @@
8
import {NodePath} from '@babel/traverse';
9
import * as t from '@babel/types';
10
import prettyFormat from 'pretty-format';
11
-import {Logger, ProgramContext} from '.';
11
+import {CompilerOutputMode, Logger, ProgramContext} from '.';
12
import {
13
HIRFunction,
14
ReactiveFunction,
@@ -24,7 +24,6 @@ import {
24
pruneUnusedLabelsHIR,
25
} from '../HIR';
26
import {
27
- CompilerMode,
27
Environment,
28
EnvironmentConfig,
29
ReactFunctionType,
@@ -120,7 +119,7 @@ function run(
119
>,
120
config: EnvironmentConfig,
121
fnType: ReactFunctionType,
123
- mode: CompilerMode,
122
+ mode: CompilerOutputMode,
123
programContext: ProgramContext,
124
logger: Logger | null,
125
filename: string | null,
@@ -170,7 +169,7 @@ function runWithEnvironment(
169
validateUseMemo(hir).unwrap();
170
171
if (
173
- env.isInferredMemoEnabled &&
172
+ env.enableDropManualMemoization &&
173
!env.config.enablePreserveExistingManualUseMemo &&
174
!env.config.disableMemoizationForDebugging &&
175
!env.config.enableChangeDetectionForDebugging
@@ -206,7 +205,7 @@ function runWithEnvironment(
205
inferTypes(hir);
206
log({kind: 'hir', name: 'InferTypes', value: hir});
207
209
- if (env.isInferredMemoEnabled) {
208
+ if (env.enableValidations) {
209
if (env.config.validateHooksUsage) {
210
validateHooksUsage(hir).unwrap();
211
}
@@ -232,13 +231,13 @@ function runWithEnvironment(
231
232
const mutabilityAliasingErrors = inferMutationAliasingEffects(hir);
233
log({kind: 'hir', name: 'InferMutationAliasingEffects', value: hir});
235
- if (env.isInferredMemoEnabled) {
234
+ if (env.enableValidations) {
235
if (mutabilityAliasingErrors.isErr()) {
236
throw mutabilityAliasingErrors.unwrapErr();
237
}
238
}
239
241
- if (env.config.enableOptimizeForSSR) {
240
+ if (env.outputMode === 'ssr') {
241
optimizeForSSR(hir);
242
log({kind: 'hir', name: 'OptimizeForSSR', value: hir});
243
}
@@ -259,14 +258,14 @@ function runWithEnvironment(
258
isFunctionExpression: false,
259
});
260
log({kind: 'hir', name: 'InferMutationAliasingRanges', value: hir});
262
- if (env.isInferredMemoEnabled) {
261
+ if (env.enableValidations) {
262
if (mutabilityAliasingRangeErrors.isErr()) {
263
throw mutabilityAliasingRangeErrors.unwrapErr();
264
}
265
validateLocalsNotReassignedAfterRender(hir);
266
}
267
269
- if (env.isInferredMemoEnabled) {
268
+ if (env.enableValidations) {
269
if (env.config.assertValidMutableRanges) {
270
assertValidMutableRanges(hir);
271
}
@@ -310,20 +309,18 @@ function runWithEnvironment(
309
value: hir,
310
});
311
313
- if (env.isInferredMemoEnabled) {
314
- if (env.config.validateStaticComponents) {
315
- env.logErrors(validateStaticComponents(hir));
316
- }
312
+ if (env.enableValidations && env.config.validateStaticComponents) {
313
+ env.logErrors(validateStaticComponents(hir));
314
+ }
315
316
+ if (env.enableMemoization) {
317
/**
318
* Only create reactive scopes (which directly map to generated memo blocks)
319
* if inferred memoization is enabled. This makes all later passes which
320
* transform reactive-scope labeled instructions no-ops.
321
*/
323
- if (!env.config.enableOptimizeForSSR) {
324
- inferReactiveScopeVariables(hir);
325
- log({kind: 'hir', name: 'InferReactiveScopeVariables', value: hir});
326
- }
322
+ inferReactiveScopeVariables(hir);
323
+ log({kind: 'hir', name: 'InferReactiveScopeVariables', value: hir});
324
}
325
326
const fbtOperands = memoizeFbtAndMacroOperandsInSameScope(hir);
@@ -588,7 +585,7 @@ export function compileFn(
585
>,
586
config: EnvironmentConfig,
587
fnType: ReactFunctionType,
591
- mode: CompilerMode,
588
+ mode: CompilerOutputMode,
589
programContext: ProgramContext,
590
logger: Logger | null,
591
filename: string | null,
compiler/packages/babel-plugin-react-compiler/src/Entrypoint/Program.ts
+28
-8
@@ -24,6 +24,7 @@ import {
24
validateRestrictedImports,
25
} from './Imports';
26
import {
27
+ CompilerOutputMode,
28
CompilerReactTarget,
29
ParsedPluginOptions,
30
PluginOptions,
@@ -421,9 +422,17 @@ export function compileProgram(
422
);
423
const compiledFns: Array<CompileResult> = [];
424
425
+ // outputMode takes precedence if specified
426
+ const outputMode: CompilerOutputMode =
427
+ pass.opts.outputMode ?? (pass.opts.noEmit ? 'lint' : 'client');
428
while (queue.length !== 0) {
429
const current = queue.shift()!;
426
- const compiled = processFn(current.fn, current.fnType, programContext);
430
+ const compiled = processFn(
431
+ current.fn,
432
+ current.fnType,
433
+ programContext,
434
+ outputMode,
435
+ );
436
437
if (compiled != null) {
438
for (const outlined of compiled.outlined) {
@@ -581,6 +590,7 @@ function processFn(
590
fn: BabelFn,
591
fnType: ReactFunctionType,
592
programContext: ProgramContext,
593
+ outputMode: CompilerOutputMode,
594
): null | CodegenFunction {
595
let directives: {
596
optIn: t.Directive | null;
@@ -616,18 +626,27 @@ function processFn(
626
}
627
628
let compiledFn: CodegenFunction;
619
- const compileResult = tryCompileFunction(fn, fnType, programContext);
629
+ const compileResult = tryCompileFunction(
630
+ fn,
631
+ fnType,
632
+ programContext,
633
+ outputMode,
634
+ );
635
if (compileResult.kind === 'error') {
636
if (directives.optOut != null) {
637
logError(compileResult.error, programContext, fn.node.loc ?? null);
638
} else {
639
handleError(compileResult.error, programContext, fn.node.loc ?? null);
640
}
626
- const retryResult = retryCompileFunction(fn, fnType, programContext);
627
- if (retryResult == null) {
641
+ if (outputMode === 'client') {
642
+ const retryResult = retryCompileFunction(fn, fnType, programContext);
643
+ if (retryResult == null) {
644
+ return null;
645
+ }
646
+ compiledFn = retryResult;
647
+ } else {
648
return null;
649
}
630
- compiledFn = retryResult;
650
} else {
651
compiledFn = compileResult.compiledFn;
652
}
@@ -663,7 +682,7 @@ function processFn(
682
683
if (programContext.hasModuleScopeOptOut) {
684
return null;
666
- } else if (programContext.opts.noEmit) {
685
+ } else if (programContext.opts.outputMode === 'lint') {
686
/**
687
* inferEffectDependencies + noEmit is currently only used for linting. In
688
* this mode, add source locations for where the compiler *can* infer effect
@@ -693,6 +712,7 @@ function tryCompileFunction(
712
fn: BabelFn,
713
fnType: ReactFunctionType,
714
programContext: ProgramContext,
715
+ outputMode: CompilerOutputMode,
716
):
717
| {kind: 'compile'; compiledFn: CodegenFunction}
718
| {kind: 'error'; error: unknown} {
@@ -719,7 +739,7 @@ function tryCompileFunction(
739
fn,
740
programContext.opts.environment,
741
fnType,
722
- 'all_features',
742
+ outputMode,
743
programContext,
744
programContext.opts.logger,
745
programContext.filename,
@@ -757,7 +777,7 @@ function retryCompileFunction(
777
fn,
778
environment,
779
fnType,
760
- 'no_inferred_memo',
780
+ 'client-no-memo',
781
programContext,
782
programContext.opts.logger,
783
programContext.filename,
compiler/packages/babel-plugin-react-compiler/src/HIR/Environment.ts
+64
-8
@@ -9,7 +9,7 @@ import * as t from '@babel/types';
9
import {ZodError, z} from 'zod/v4';
10
import {fromZodError} from 'zod-validation-error/v4';
11
import {CompilerError} from '../CompilerError';
12
-import {Logger, ProgramContext} from '../Entrypoint';
12
+import {CompilerOutputMode, Logger, ProgramContext} from '../Entrypoint';
13
import {Err, Ok, Result} from '../Utils/Result';
14
import {
15
DEFAULT_GLOBALS,
@@ -51,6 +51,7 @@ import {Scope as BabelScope, NodePath} from '@babel/traverse';
51
import {TypeSchema} from './TypeSchema';
52
import {FlowTypeEnv} from '../Flood/Types';
53
import {defaultModuleTypeProvider} from './DefaultModuleTypeProvider';
54
+import {assertExhaustive} from '../Utils/utils';
55
56
export const ReactElementSymbolSchema = z.object({
57
elementSymbol: z.union([
@@ -691,8 +692,6 @@ export const EnvironmentConfigSchema = z.object({
692
* by React to only execute in response to events, not during render.
693
*/
694
enableInferEventHandlers: z.boolean().default(false),
694
-
695
- enableOptimizeForSSR: z.boolean().default(false),
695
});
696
697
export type EnvironmentConfig = z.infer<typeof EnvironmentConfigSchema>;
@@ -732,7 +731,7 @@ export class Environment {
731
code: string | null;
732
config: EnvironmentConfig;
733
fnType: ReactFunctionType;
735
- compilerMode: CompilerMode;
734
+ outputMode: CompilerOutputMode;
735
programContext: ProgramContext;
736
hasFireRewrite: boolean;
737
hasInferredEffect: boolean;
@@ -747,7 +746,7 @@ export class Environment {
746
constructor(
747
scope: BabelScope,
748
fnType: ReactFunctionType,
750
- compilerMode: CompilerMode,
749
+ outputMode: CompilerOutputMode,
750
config: EnvironmentConfig,
751
contextIdentifiers: Set<t.Identifier>,
752
parentFunction: NodePath<t.Function>, // the outermost function being compiled
@@ -758,7 +757,7 @@ export class Environment {
757
) {
758
this.#scope = scope;
759
this.fnType = fnType;
761
- this.compilerMode = compilerMode;
760
+ this.outputMode = outputMode;
761
this.config = config;
762
this.filename = filename;
763
this.code = code;
@@ -854,8 +853,65 @@ export class Environment {
853
return this.#flowTypeEnvironment;
854
}
855
857
- get isInferredMemoEnabled(): boolean {
858
- return this.compilerMode !== 'no_inferred_memo';
856
+ get enableDropManualMemoization(): boolean {
857
+ switch (this.outputMode) {
858
+ case 'lint': {
859
+ // linting drops to be more compatible with compiler analysis
860
+ return true;
861
+ }
862
+ case 'client':
863
+ case 'ssr': {
864
+ return true;
865
+ }
866
+ case 'client-no-memo': {
867
+ return false;
868
+ }
869
+ default: {
870
+ assertExhaustive(
871
+ this.outputMode,
872
+ `Unexpected output mode '${this.outputMode}'`,
873
+ );
874
+ }
875
+ }
876
+ }
877
+
878
+ get enableMemoization(): boolean {
879
+ switch (this.outputMode) {
880
+ case 'client':
881
+ case 'lint': {
882
+ // linting also enables memoization so that we can check if manual memoization is preserved
883
+ return true;
884
+ }
885
+ case 'ssr':
886
+ case 'client-no-memo': {
887
+ return false;
888
+ }
889
+ default: {
890
+ assertExhaustive(
891
+ this.outputMode,
892
+ `Unexpected output mode '${this.outputMode}'`,
893
+ );
894
+ }
895
+ }
896
+ }
897
+
898
+ get enableValidations(): boolean {
899
+ switch (this.outputMode) {
900
+ case 'client':
901
+ case 'lint':
902
+ case 'ssr': {
903
+ return true;
904
+ }
905
+ case 'client-no-memo': {
906
+ return false;
907
+ }
908
+ default: {
909
+ assertExhaustive(
910
+ this.outputMode,
911
+ `Unexpected output mode '${this.outputMode}'`,
912
+ );
913
+ }
914
+ }
915
}
916
917
get nextIdentifierId(): IdentifierId {
compiler/packages/babel-plugin-react-compiler/src/Inference/InferMutationAliasingEffects.ts
+1
-1
@@ -2452,7 +2452,7 @@ function computeEffectsForLegacySignature(
2452
}),
2453
});
2454
}
2455
- if (signature.knownIncompatible != null && state.env.isInferredMemoEnabled) {
2455
+ if (signature.knownIncompatible != null && state.env.enableValidations) {
2456
const errors = new CompilerError();
2457
errors.pushDiagnostic(
2458
CompilerDiagnostic.create({
compiler/packages/babel-plugin-react-compiler/src/Optimization/DeadCodeElimination.ts
+1
-1
@@ -319,7 +319,7 @@ function pruneableValue(value: InstructionValue, state: State): boolean {
319
}
320
case 'CallExpression':
321
case 'MethodCall': {
322
- if (state.env.config.enableOptimizeForSSR) {
322
+ if (state.env.outputMode === 'ssr') {
323
const calleee =
324
value.kind === 'CallExpression' ? value.callee : value.property;
325
const hookKind = getHookKind(state.env, calleee.identifier);
compiler/packages/babel-plugin-react-compiler/src/ReactiveScopes/CodegenReactiveFunction.ts
+7
-4
@@ -159,7 +159,7 @@ export function codegenFunction(
159
const compiled = compileResult.unwrap();
160
161
const hookGuard = fn.env.config.enableEmitHookGuards;
162
- if (hookGuard != null && fn.env.isInferredMemoEnabled) {
162
+ if (hookGuard != null && fn.env.outputMode === 'client') {
163
compiled.body = t.blockStatement([
164
createHookGuard(
165
hookGuard,
@@ -259,7 +259,7 @@ export function codegenFunction(
259
if (
260
emitInstrumentForget != null &&
261
fn.id != null &&
262
- fn.env.isInferredMemoEnabled
262
+ fn.env.outputMode === 'client'
263
) {
264
/*
265
* Technically, this is a conditional hook call. However, we expect
@@ -591,7 +591,10 @@ function codegenBlockNoReset(
591
}
592
593
function wrapCacheDep(cx: Context, value: t.Expression): t.Expression {
594
- if (cx.env.config.enableEmitFreeze != null && cx.env.isInferredMemoEnabled) {
594
+ if (
595
+ cx.env.config.enableEmitFreeze != null &&
596
+ cx.env.outputMode === 'client'
597
+ ) {
598
const emitFreezeIdentifier = cx.env.programContext.addImportSpecifier(
599
cx.env.config.enableEmitFreeze,
600
).name;
@@ -1772,7 +1775,7 @@ function createCallExpression(
1775
}
1776
1777
const hookGuard = env.config.enableEmitHookGuards;
1775
- if (hookGuard != null && isHook && env.isInferredMemoEnabled) {
1778
+ if (hookGuard != null && isHook && env.outputMode === 'client') {
1779
const iife = t.functionExpression(
1780
null,
1781
[],
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-noemit.expect.md
+2
-2
@@ -2,7 +2,7 @@
2
## Input
3
4
```javascript
5
-// @dynamicGating:{"source":"shared-runtime"} @noEmit
5
+// @dynamicGating:{"source":"shared-runtime"} @outputMode:"lint"
6
7
function Foo() {
8
'use memo if(getTrue)';
@@ -19,7 +19,7 @@ export const FIXTURE_ENTRYPOINT = {
19
## Code
20
21
```javascript
22
-// @dynamicGating:{"source":"shared-runtime"} @noEmit
22
+// @dynamicGating:{"source":"shared-runtime"} @outputMode:"lint"
23
24
function Foo() {
25
"use memo if(getTrue)";
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/gating/dynamic-gating-noemit.js
+1
-1
@@ -1,4 +1,4 @@
1
-// @dynamicGating:{"source":"shared-runtime"} @noEmit
1
+// @dynamicGating:{"source":"shared-runtime"} @outputMode:"lint"
2
3
function Foo() {
4
'use memo if(getTrue)';
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/no-emit/retry-no-emit.expect.md
deleted
-66
@@ -1,66 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly
6
-import {print} from 'shared-runtime';
7
-import useEffectWrapper from 'useEffectWrapper';
8
-import {AUTODEPS} from 'react';
9
-
10
-function Foo({propVal}) {
11
- const arr = [propVal];
12
- useEffectWrapper(() => print(arr), AUTODEPS);
13
-
14
- const arr2 = [];
15
- useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
16
- arr2.push(2);
17
- return {arr, arr2};
18
-}
19
-
20
-export const FIXTURE_ENTRYPOINT = {
21
- fn: Foo,
22
- params: [{propVal: 1}],
23
- sequentialRenders: [{propVal: 1}, {propVal: 2}],
24
-};
25
-
26
-```
27
-
28
-## Code
29
-
30
-```javascript
31
-// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly
32
-import { print } from "shared-runtime";
33
-import useEffectWrapper from "useEffectWrapper";
34
-import { AUTODEPS } from "react";
35
-
36
-function Foo({ propVal }) {
37
- const arr = [propVal];
38
- useEffectWrapper(() => print(arr), AUTODEPS);
39
-
40
- const arr2 = [];
41
- useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
42
- arr2.push(2);
43
- return { arr, arr2 };
44
-}
45
-
46
-export const FIXTURE_ENTRYPOINT = {
47
- fn: Foo,
48
- params: [{ propVal: 1 }],
49
- sequentialRenders: [{ propVal: 1 }, { propVal: 2 }],
50
-};
51
-
52
-```
53
-
54
-## Logs
55
-
56
-```
57
-{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":195},"end":{"line":14,"column":1,"index":409},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":372},"end":{"line":12,"column":6,"index":376},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}}
58
-{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":248},"end":{"line":8,"column":46,"index":292},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":8,"column":31,"index":277},"end":{"line":8,"column":34,"index":280},"filename":"retry-no-emit.ts","identifierName":"arr"}]}
59
-{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":11,"column":2,"index":316},"end":{"line":11,"column":54,"index":368},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":11,"column":25,"index":339},"end":{"line":11,"column":29,"index":343},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":25,"index":339},"end":{"line":11,"column":29,"index":343},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":35,"index":349},"end":{"line":11,"column":42,"index":356},"filename":"retry-no-emit.ts","identifierName":"propVal"}]}
60
-{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":195},"end":{"line":14,"column":1,"index":409},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
61
-```
62
-
63
-### Eval output
64
-(kind: ok) {"arr":[1],"arr2":[2]}
65
-{"arr":[2],"arr2":[2]}
66
-logs: [[ 1 ],[ 2 ]]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/error.infer-effect-deps-with-rule-violation--lint.expect.md
new
+48
@@ -0,0 +1,48 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @inferEffectDependencies @outputMode:"lint" @panicThreshold:"none"
6
+import {print} from 'shared-runtime';
7
+import useEffectWrapper from 'useEffectWrapper';
8
+import {AUTODEPS} from 'react';
9
+
10
+function Foo({propVal}) {
11
+ const arr = [propVal];
12
+ useEffectWrapper(() => print(arr), AUTODEPS);
13
+
14
+ const arr2 = [];
15
+ useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
16
+ arr2.push(2);
17
+ return {arr, arr2};
18
+}
19
+
20
+export const FIXTURE_ENTRYPOINT = {
21
+ fn: Foo,
22
+ params: [{propVal: 1}],
23
+ sequentialRenders: [{propVal: 1}, {propVal: 2}],
24
+};
25
+
26
+```
27
+
28
+
29
+## Error
30
+
31
+```
32
+Found 1 error:
33
+
34
+Error: Cannot infer dependencies of this effect. This will break your build!
35
+
36
+To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
37
+
38
+error.infer-effect-deps-with-rule-violation--lint.ts:8:2
39
+ 6 | function Foo({propVal}) {
40
+ 7 | const arr = [propVal];
41
+> 8 | useEffectWrapper(() => print(arr), AUTODEPS);
42
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
43
+ 9 |
44
+ 10 | const arr2 = [];
45
+ 11 | useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
46
+```
47
+
48
+
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/error.infer-effect-deps-with-rule-violation--lint.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly
1
+// @inferEffectDependencies @outputMode:"lint" @panicThreshold:"none"
2
import {print} from 'shared-runtime';
3
import useEffectWrapper from 'useEffectWrapper';
4
import {AUTODEPS} from 'react';
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/error.infer-effect-deps-with-rule-violation-use-memo-opt-in--lint.expect.md
new
+49
@@ -0,0 +1,49 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @inferEffectDependencies @outputMode:"lint" @panicThreshold:"none"
6
+import {print} from 'shared-runtime';
7
+import useEffectWrapper from 'useEffectWrapper';
8
+import {AUTODEPS} from 'react';
9
+
10
+function Foo({propVal}) {
11
+ 'use memo';
12
+ const arr = [propVal];
13
+ useEffectWrapper(() => print(arr), AUTODEPS);
14
+
15
+ const arr2 = [];
16
+ useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
17
+ arr2.push(2);
18
+ return {arr, arr2};
19
+}
20
+
21
+export const FIXTURE_ENTRYPOINT = {
22
+ fn: Foo,
23
+ params: [{propVal: 1}],
24
+ sequentialRenders: [{propVal: 1}, {propVal: 2}],
25
+};
26
+
27
+```
28
+
29
+
30
+## Error
31
+
32
+```
33
+Found 1 error:
34
+
35
+Error: Cannot infer dependencies of this effect. This will break your build!
36
+
37
+To resolve, either pass a dependency array or fix reported compiler bailout diagnostics.
38
+
39
+error.infer-effect-deps-with-rule-violation-use-memo-opt-in--lint.ts:9:2
40
+ 7 | 'use memo';
41
+ 8 | const arr = [propVal];
42
+> 9 | useEffectWrapper(() => print(arr), AUTODEPS);
43
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Cannot infer dependencies
44
+ 10 |
45
+ 11 | const arr2 = [];
46
+ 12 | useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
47
+```
48
+
49
+
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/error.infer-effect-deps-with-rule-violation-use-memo-opt-in--lint.js
renamed
+2
-3
@@ -1,7 +1,7 @@
1
-// @compilationMode:"all" @inferEffectDependencies @panicThreshold:"none" @noEmit
1
+// @inferEffectDependencies @outputMode:"lint" @panicThreshold:"none"
2
import {print} from 'shared-runtime';
3
-import {AUTODEPS} from 'react';
3
import useEffectWrapper from 'useEffectWrapper';
4
+import {AUTODEPS} from 'react';
5
6
function Foo({propVal}) {
7
'use memo';
@@ -11,7 +11,6 @@ function Foo({propVal}) {
11
const arr2 = [];
12
useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
13
arr2.push(2);
14
-
14
return {arr, arr2};
15
}
16
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/infer-effect-deps-with-rule-violation--compile.expect.md
new
+58
@@ -0,0 +1,58 @@
1
+
2
+## Input
3
+
4
+```javascript
5
+// @inferEffectDependencies @panicThreshold:"none"
6
+import {print} from 'shared-runtime';
7
+import useEffectWrapper from 'useEffectWrapper';
8
+import {AUTODEPS} from 'react';
9
+
10
+function Foo({propVal}) {
11
+ const arr = [propVal];
12
+ useEffectWrapper(() => print(arr), AUTODEPS);
13
+
14
+ const arr2 = [];
15
+ useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
16
+ arr2.push(2);
17
+ return {arr, arr2};
18
+}
19
+
20
+export const FIXTURE_ENTRYPOINT = {
21
+ fn: Foo,
22
+ params: [{propVal: 1}],
23
+ sequentialRenders: [{propVal: 1}, {propVal: 2}],
24
+};
25
+
26
+```
27
+
28
+## Code
29
+
30
+```javascript
31
+// @inferEffectDependencies @panicThreshold:"none"
32
+import { print } from "shared-runtime";
33
+import useEffectWrapper from "useEffectWrapper";
34
+import { AUTODEPS } from "react";
35
+
36
+function Foo(t0) {
37
+ const { propVal } = t0;
38
+ const arr = [propVal];
39
+ useEffectWrapper(() => print(arr), [arr]);
40
+
41
+ const arr2 = [];
42
+ useEffectWrapper(() => arr2.push(propVal), [arr2, propVal]);
43
+ arr2.push(2);
44
+ return { arr, arr2 };
45
+}
46
+
47
+export const FIXTURE_ENTRYPOINT = {
48
+ fn: Foo,
49
+ params: [{ propVal: 1 }],
50
+ sequentialRenders: [{ propVal: 1 }, { propVal: 2 }],
51
+};
52
+
53
+```
54
+
55
+### Eval output
56
+(kind: ok) {"arr":[1],"arr2":[2]}
57
+{"arr":[2],"arr2":[2]}
58
+logs: [[ 1 ],[ 2 ]]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/infer-effect-deps-with-rule-violation--compile.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
1
+// @inferEffectDependencies @panicThreshold:"none"
2
import {print} from 'shared-runtime';
3
import useEffectWrapper from 'useEffectWrapper';
4
import {AUTODEPS} from 'react';
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/infer-effect-deps-with-rule-violation-use-memo-opt-in--compile.expect.md
renamed
+9
-9
@@ -2,10 +2,10 @@
2
## Input
3
4
```javascript
5
-// @compilationMode:"all" @inferEffectDependencies @panicThreshold:"none" @noEmit
5
+// @inferEffectDependencies @panicThreshold:"none"
6
import {print} from 'shared-runtime';
7
-import {AUTODEPS} from 'react';
7
import useEffectWrapper from 'useEffectWrapper';
8
+import {AUTODEPS} from 'react';
9
10
function Foo({propVal}) {
11
'use memo';
@@ -15,7 +15,6 @@ function Foo({propVal}) {
15
const arr2 = [];
16
useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
17
arr2.push(2);
18
-
18
return {arr, arr2};
19
}
20
@@ -30,20 +29,21 @@ export const FIXTURE_ENTRYPOINT = {
29
## Code
30
31
```javascript
33
-// @compilationMode:"all" @inferEffectDependencies @panicThreshold:"none" @noEmit
32
+// @inferEffectDependencies @panicThreshold:"none"
33
import { print } from "shared-runtime";
35
-import { AUTODEPS } from "react";
34
import useEffectWrapper from "useEffectWrapper";
35
+import { AUTODEPS } from "react";
36
38
-function Foo({ propVal }) {
37
+function Foo(t0) {
38
"use memo";
39
+ const { propVal } = t0;
40
+
41
const arr = [propVal];
41
- useEffectWrapper(() => print(arr), AUTODEPS);
42
+ useEffectWrapper(() => print(arr), [arr]);
43
44
const arr2 = [];
44
- useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
45
+ useEffectWrapper(() => arr2.push(propVal), [arr2, propVal]);
46
arr2.push(2);
46
-
47
return { arr, arr2 };
48
}
49
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/infer-effect-deps-with-rule-violation-use-memo-opt-in--compile.js
new
+21
@@ -0,0 +1,21 @@
1
+// @inferEffectDependencies @panicThreshold:"none"
2
+import {print} from 'shared-runtime';
3
+import useEffectWrapper from 'useEffectWrapper';
4
+import {AUTODEPS} from 'react';
5
+
6
+function Foo({propVal}) {
7
+ 'use memo';
8
+ const arr = [propVal];
9
+ useEffectWrapper(() => print(arr), AUTODEPS);
10
+
11
+ const arr2 = [];
12
+ useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
13
+ arr2.push(2);
14
+ return {arr, arr2};
15
+}
16
+
17
+export const FIXTURE_ENTRYPOINT = {
18
+ fn: Foo,
19
+ params: [{propVal: 1}],
20
+ sequentialRenders: [{propVal: 1}, {propVal: 2}],
21
+};
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/lint-repro.expect.md
renamed
+2
-2
@@ -2,7 +2,7 @@
2
## Input
3
4
```javascript
5
-// @inferEffectDependencies @noEmit
5
+// @inferEffectDependencies @outputMode:"lint"
6
import {print} from 'shared-runtime';
7
import useEffectWrapper from 'useEffectWrapper';
8
import {AUTODEPS} from 'react';
@@ -17,7 +17,7 @@ function ReactiveVariable({propVal}) {
17
## Code
18
19
```javascript
20
-// @inferEffectDependencies @noEmit
20
+// @inferEffectDependencies @outputMode:"lint"
21
import { print } from "shared-runtime";
22
import useEffectWrapper from "useEffectWrapper";
23
import { AUTODEPS } from "react";
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/infer-effect-dependencies/retry-lint-comparison/lint-repro.js
renamed
+1
-1
@@ -1,4 +1,4 @@
1
-// @inferEffectDependencies @noEmit
1
+// @inferEffectDependencies @outputMode:"lint"
2
import {print} from 'shared-runtime';
3
import useEffectWrapper from 'useEffectWrapper';
4
import {AUTODEPS} from 'react';
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/new-mutability/retry-no-emit.expect.md
deleted
-66
@@ -1,66 +0,0 @@
1
-
2
-## Input
3
-
4
-```javascript
5
-// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
6
-import {print} from 'shared-runtime';
7
-import useEffectWrapper from 'useEffectWrapper';
8
-import {AUTODEPS} from 'react';
9
-
10
-function Foo({propVal}) {
11
- const arr = [propVal];
12
- useEffectWrapper(() => print(arr), AUTODEPS);
13
-
14
- const arr2 = [];
15
- useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
16
- arr2.push(2);
17
- return {arr, arr2};
18
-}
19
-
20
-export const FIXTURE_ENTRYPOINT = {
21
- fn: Foo,
22
- params: [{propVal: 1}],
23
- sequentialRenders: [{propVal: 1}, {propVal: 2}],
24
-};
25
-
26
-```
27
-
28
-## Code
29
-
30
-```javascript
31
-// @inferEffectDependencies @noEmit @panicThreshold:"none" @loggerTestOnly @enableNewMutationAliasingModel
32
-import { print } from "shared-runtime";
33
-import useEffectWrapper from "useEffectWrapper";
34
-import { AUTODEPS } from "react";
35
-
36
-function Foo({ propVal }) {
37
- const arr = [propVal];
38
- useEffectWrapper(() => print(arr), AUTODEPS);
39
-
40
- const arr2 = [];
41
- useEffectWrapper(() => arr2.push(propVal), AUTODEPS);
42
- arr2.push(2);
43
- return { arr, arr2 };
44
-}
45
-
46
-export const FIXTURE_ENTRYPOINT = {
47
- fn: Foo,
48
- params: [{ propVal: 1 }],
49
- sequentialRenders: [{ propVal: 1 }, { propVal: 2 }],
50
-};
51
-
52
-```
53
-
54
-## Logs
55
-
56
-```
57
-{"kind":"CompileError","fnLoc":{"start":{"line":6,"column":0,"index":227},"end":{"line":14,"column":1,"index":441},"filename":"retry-no-emit.ts"},"detail":{"options":{"category":"Immutability","reason":"This value cannot be modified","description":"Modifying a value previously passed as an argument to a hook is not allowed. Consider moving the modification before calling the hook","details":[{"kind":"error","loc":{"start":{"line":12,"column":2,"index":404},"end":{"line":12,"column":6,"index":408},"filename":"retry-no-emit.ts","identifierName":"arr2"},"message":"value cannot be modified"}]}}}
58
-{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":8,"column":2,"index":280},"end":{"line":8,"column":46,"index":324},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":8,"column":31,"index":309},"end":{"line":8,"column":34,"index":312},"filename":"retry-no-emit.ts","identifierName":"arr"}]}
59
-{"kind":"AutoDepsDecorations","fnLoc":{"start":{"line":11,"column":2,"index":348},"end":{"line":11,"column":54,"index":400},"filename":"retry-no-emit.ts"},"decorations":[{"start":{"line":11,"column":25,"index":371},"end":{"line":11,"column":29,"index":375},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":25,"index":371},"end":{"line":11,"column":29,"index":375},"filename":"retry-no-emit.ts","identifierName":"arr2"},{"start":{"line":11,"column":35,"index":381},"end":{"line":11,"column":42,"index":388},"filename":"retry-no-emit.ts","identifierName":"propVal"}]}
60
-{"kind":"CompileSuccess","fnLoc":{"start":{"line":6,"column":0,"index":227},"end":{"line":14,"column":1,"index":441},"filename":"retry-no-emit.ts"},"fnName":"Foo","memoSlots":0,"memoBlocks":0,"memoValues":0,"prunedMemoBlocks":0,"prunedMemoValues":0}
61
-```
62
-
63
-### Eval output
64
-(kind: ok) {"arr":[1],"arr2":[2]}
65
-{"arr":[2],"arr2":[2]}
66
-logs: [[ 1 ],[ 2 ]]
\ No newline at end of file
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssr/optimize-ssr.expect.md
+33
-3
@@ -20,10 +20,40 @@ function Component() {
20
## Code
21
22
```javascript
23
-// @enableOptimizeForSSR
23
+import { c as _c } from "react/compiler-runtime"; // @enableOptimizeForSSR
24
function Component() {
25
- const state = 0;
26
- return <input value={state} />;
25
+ const $ = _c(4);
26
+ const [state, setState] = useState(0);
27
+ const ref = useRef(null);
28
+ let t0;
29
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
30
+ t0 = (e) => {
31
+ setState(e.target.value);
32
+ };
33
+ $[0] = t0;
34
+ } else {
35
+ t0 = $[0];
36
+ }
37
+ const onChange = t0;
38
+ let t1;
39
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
40
+ t1 = () => {
41
+ log(ref.current.value);
42
+ };
43
+ $[1] = t1;
44
+ } else {
45
+ t1 = $[1];
46
+ }
47
+ useEffect(t1);
48
+ let t2;
49
+ if ($[2] !== state) {
50
+ t2 = <input value={state} onChange={onChange} ref={ref} />;
51
+ $[2] = state;
52
+ $[3] = t2;
53
+ } else {
54
+ t2 = $[3];
55
+ }
56
+ return t2;
57
}
58
59
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssr/ssr-infer-event-handlers-from-setState.expect.md
+32
-4
@@ -22,12 +22,40 @@ function Component() {
22
## Code
23
24
```javascript
25
-// @enableOptimizeForSSR
25
+import { c as _c } from "react/compiler-runtime"; // @enableOptimizeForSSR
26
function Component() {
27
- const state = 0;
27
+ const $ = _c(4);
28
+ const [state, setState] = useState(0);
29
const ref = useRef(null);
29
- const onChange = undefined;
30
- return <CustomInput value={state} onChange={onChange} ref={ref} />;
30
+ let t0;
31
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
32
+ t0 = (e) => {
33
+ setState(e.target.value);
34
+ };
35
+ $[0] = t0;
36
+ } else {
37
+ t0 = $[0];
38
+ }
39
+ const onChange = t0;
40
+ let t1;
41
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
42
+ t1 = () => {
43
+ log(ref.current.value);
44
+ };
45
+ $[1] = t1;
46
+ } else {
47
+ t1 = $[1];
48
+ }
49
+ useEffect(t1);
50
+ let t2;
51
+ if ($[2] !== state) {
52
+ t2 = <CustomInput value={state} onChange={onChange} ref={ref} />;
53
+ $[2] = state;
54
+ $[3] = t2;
55
+ } else {
56
+ t2 = $[3];
57
+ }
58
+ return t2;
59
}
60
61
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssr/ssr-infer-event-handlers-from-startTransition.expect.md
+35
-5
@@ -25,13 +25,43 @@ function Component() {
25
## Code
26
27
```javascript
28
-// @enableOptimizeForSSR
28
+import { c as _c } from "react/compiler-runtime"; // @enableOptimizeForSSR
29
function Component() {
30
- useTransition();
31
- const state = 0;
30
+ const $ = _c(4);
31
+ const [, startTransition] = useTransition();
32
+ const [state, setState] = useState(0);
33
const ref = useRef(null);
33
- const onChange = undefined;
34
- return <CustomInput value={state} onChange={onChange} ref={ref} />;
34
+ let t0;
35
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
36
+ t0 = (e) => {
37
+ startTransition(() => {
38
+ setState.call(null, e.target.value);
39
+ });
40
+ };
41
+ $[0] = t0;
42
+ } else {
43
+ t0 = $[0];
44
+ }
45
+ const onChange = t0;
46
+ let t1;
47
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
48
+ t1 = () => {
49
+ log(ref.current.value);
50
+ };
51
+ $[1] = t1;
52
+ } else {
53
+ t1 = $[1];
54
+ }
55
+ useEffect(t1);
56
+ let t2;
57
+ if ($[2] !== state) {
58
+ t2 = <CustomInput value={state} onChange={onChange} ref={ref} />;
59
+ $[2] = state;
60
+ $[3] = t2;
61
+ } else {
62
+ t2 = $[3];
63
+ }
64
+ return t2;
65
}
66
67
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssr/ssr-use-reducer-initializer.expect.md
+36
-3
@@ -25,7 +25,7 @@ function Component() {
25
## Code
26
27
```javascript
28
-// @enableOptimizeForSSR
28
+import { c as _c } from "react/compiler-runtime"; // @enableOptimizeForSSR
29
30
import { useReducer } from "react";
31
@@ -34,8 +34,41 @@ const initializer = (x) => {
34
};
35
36
function Component() {
37
- const state = initializer(0);
38
- return <input value={state} />;
37
+ const $ = _c(4);
38
+ const [state, dispatch] = useReducer(_temp, 0, initializer);
39
+ const ref = useRef(null);
40
+ let t0;
41
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
42
+ t0 = (e) => {
43
+ dispatch(e.target.value);
44
+ };
45
+ $[0] = t0;
46
+ } else {
47
+ t0 = $[0];
48
+ }
49
+ const onChange = t0;
50
+ let t1;
51
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
52
+ t1 = () => {
53
+ log(ref.current.value);
54
+ };
55
+ $[1] = t1;
56
+ } else {
57
+ t1 = $[1];
58
+ }
59
+ useEffect(t1);
60
+ let t2;
61
+ if ($[2] !== state) {
62
+ t2 = <input value={state} onChange={onChange} ref={ref} />;
63
+ $[2] = state;
64
+ $[3] = t2;
65
+ } else {
66
+ t2 = $[3];
67
+ }
68
+ return t2;
69
+}
70
+function _temp(_, next) {
71
+ return next;
72
}
73
74
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/ssr/ssr-use-reducer.expect.md
+36
-3
@@ -23,13 +23,46 @@ function Component() {
23
## Code
24
25
```javascript
26
-// @enableOptimizeForSSR
26
+import { c as _c } from "react/compiler-runtime"; // @enableOptimizeForSSR
27
28
import { useReducer } from "react";
29
30
function Component() {
31
- const state = 0;
32
- return <input value={state} />;
31
+ const $ = _c(4);
32
+ const [state, dispatch] = useReducer(_temp, 0);
33
+ const ref = useRef(null);
34
+ let t0;
35
+ if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
36
+ t0 = (e) => {
37
+ dispatch(e.target.value);
38
+ };
39
+ $[0] = t0;
40
+ } else {
41
+ t0 = $[0];
42
+ }
43
+ const onChange = t0;
44
+ let t1;
45
+ if ($[1] === Symbol.for("react.memo_cache_sentinel")) {
46
+ t1 = () => {
47
+ log(ref.current.value);
48
+ };
49
+ $[1] = t1;
50
+ } else {
51
+ t1 = $[1];
52
+ }
53
+ useEffect(t1);
54
+ let t2;
55
+ if ($[2] !== state) {
56
+ t2 = <input value={state} onChange={onChange} ref={ref} />;
57
+ $[2] = state;
58
+ $[3] = t2;
59
+ } else {
60
+ t2 = $[3];
61
+ }
62
+ return t2;
63
+}
64
+function _temp(_, next) {
65
+ return next;
66
}
67
68
```
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-memo-noemit.expect.md
+2
-2
@@ -2,7 +2,7 @@
2
## Input
3
4
```javascript
5
-// @noEmit
5
+// @outputMode:"lint"
6
7
function Foo() {
8
'use memo';
@@ -19,7 +19,7 @@ export const FIXTURE_ENTRYPOINT = {
19
## Code
20
21
```javascript
22
-// @noEmit
22
+// @outputMode:"lint"
23
24
function Foo() {
25
"use memo";
compiler/packages/babel-plugin-react-compiler/src/__tests__/fixtures/compiler/use-memo-noemit.js
+1
-1
@@ -1,4 +1,4 @@
1
-// @noEmit
1
+// @outputMode:"lint"
2
3
function Foo() {
4
'use memo';
compiler/packages/eslint-plugin-react-compiler/src/shared/RunReactCompiler.ts
+1
-1
@@ -21,7 +21,7 @@ import {isDeepStrictEqual} from 'util';
21
import type {ParseResult} from '@babel/parser';
22
23
const COMPILER_OPTIONS: PluginOptions = {
24
- noEmit: true,
24
+ outputMode: 'lint',
25
panicThreshold: 'none',
26
// Don't emit errors on Flow suppressions--Flow already gave a signal
27
flowSuppressions: false,
packages/eslint-plugin-react-hooks/src/shared/RunReactCompiler.ts
+1
-1
@@ -22,7 +22,7 @@ import {isDeepStrictEqual} from 'util';
22
import type {ParseResult} from '@babel/parser';
23
24
const COMPILER_OPTIONS: PluginOptions = {
25
- noEmit: true,
25
+ outputMode: 'lint',
26
panicThreshold: 'none',
27
// Don't emit errors on Flow suppressions--Flow already gave a signal
28
flowSuppressions: false,