Skip to content

feat: Extends performance domain with React Compiler error triage and coverage antipatterns - #170

Merged
MajorLift merged 10 commits into
mainfrom
jongsun/add/react-compiler-triage
Sep 18, 2026
Merged

MajorLift merged 10 commits into
mainfrom
jongsun/add/react-compiler-triage

Conversation

@MajorLift

@MajorLift MajorLift commented Sep 18, 2026

Copy link
Copy Markdown
Contributor

Motivation

The React Compiler fails open. A component it cannot compile ships unoptimized with a green build and no warning, so the coverage you believe you have and the coverage you have are different numbers and nothing reports the gap.

That makes two questions urgent, in that order. Which components is it skipping, and which patterns are quietly removing components from the set it compiles.

Finding out what the compiler is skipping

Raising panicThreshold to 'all_errors' is how you see the skipped set, and it returns an error list that mixes unsupported-syntax noise with real bugs, so the list is only useful once it is sorted.

  • references/mm-react-compiler-error-triage.md sorts compiler errors into unsupported, which is the compiler's own Todo category, and actionable. It ratchets panicThreshold in non-production builds rather than setting it once, so the actionable set shrinks under a threshold that tightens instead of being read once and abandoned.
  • references/mm-react-compiler.md counts a file carrying a module-scope 'use no memo' as compiled rather than skipped, which is the measurement error that makes a coverage figure read better than the build.
  • The same file describes the compiler as running app-wide on its default target: '19', as set up in metamask-mobile#31171 (fully enable React Compiler), replacing the path allowlist and the target: '18' rule. That is the denominator the skipped set is measured against.

Coverage Anti-Patterns

Each of these removes a whole function from the compiled set, and each looks locally harmless at the call site.

  • A dependency the effect never reads. The compiler's effect-dependency validation (validateExhaustiveEffectDependencies) reports it as an error and skips the entire function. A comment beside the array does not help, because the check reads the array rather than the prose. perf-hooks-effects gains the rule with the four ways to make the array describe the code: pass the value into the work the effect starts, put a key on a component where the value marks a scope that must reset as a whole, handle it where the action occurs, or treat it as a finding. It names what does not work, which is deleting the dependency outright, explaining it in a comment, reaching for 'use no memo', and adding a parameter the callee ignores.
  • 'use no memo' left in place after the reason for it is gone. mm-react-compiler.md now tests whether the directive is doing any work before keeping it, since React documents it as a temporary debugging tool and it opts the whole function out.
  • Removing a useMemo the compiler appears to make redundant. Its memoization is not guaranteed to preserve the identity a useEffect dependency needs, so mm-react-compiler.md keeps any useMemo or useCallback whose output feeds an effect's dependency array.
  • perf-react-compiler states the unread-dependency rule as a compiler-coverage anti-pattern, because someone asking what costs them coverage opens that file rather than the effects one.

Two effects rules from the same review

These do not affect compiler coverage and are here because they came out of the same review rather than because they belong to the argument above.

  • perf-hooks-effects corrects its dependency-minimization guidance to depend on the primitive the effect reads rather than on an object the parent rebuilds each render. The previous worked pair moved refreshInterval to a default parameter and dropped it from the array, which does not change whether it is a dependency.
  • perf-hooks-effects moves a multi-step async acquire with a timeout and several end paths into a plain object owned outside React, so those end paths can be unit-tested without rendering.

Where this lands

The triage material goes to skills/performance/, which reaches mobile alone because that skill's repos/ holds only metamask-mobile.md and tools/install skips a skill entirely for any repo with no overlay file. The coverage rules go to skills/perf-*/repos/metamask-extension.md, four skills whose repos/ holds only that file.

Of the 85 lines added on the first path, 6 are mobile-specific. Of the 140 on the second, 0 are extension-specific. So most of this is platform-independent React guidance landing where the existing rules already sit. Widening either path's reach needs repos/ files in skills this pull request does not touch and is tracked separately.

The anti-patterns came out of review on metamask-extension#46240.

`mm-react-compiler-error-triage` — sorting compiler errors into `Todo`
and unsupported versus actionable, ratcheting `panicThreshold`, and the
`useMemo`/`useCallback` exception for effect dependencies, whose output the
compiler's memoization does not preserve.

Split out of #43: compiler adoption is a different subject from the render
antipattern scans, and nothing in either scan cites it.
`babel-plugin-react-compiler` 1.0.0 logs `CompileSuccess` for every function
in a file whose top-level directive then discards the transform. Only a
directive inside one function's body logs `CompileSkip`. The compiled count
therefore rises with opt-outs and is read against the opt-out count.
…s it

metamask-mobile#31171 (enable the React Compiler across the Metro bundle)
replaced the two-path allowlist. The plugin now applies to every file
except under Jest, with no `target` override, so its default of React 19
applies. The triage reference also named two internal planning tickets.
…ng it

Removing the directive and re-running the compiler settles it: zero new
errors means the directive was masking nothing.
@MajorLift
MajorLift marked this pull request as ready for review September 18, 2026 14:25
@MajorLift
MajorLift requested a review from rvelaz September 18, 2026 14:47
@MajorLift
MajorLift marked this pull request as draft September 18, 2026 14:52
It was stated only as an effects rule, and the cost it names is a compiler cost:
an entry the effect never reads makes the compiler skip the whole function, so
the hook ships unmemoized. Someone asking what loses them compiler coverage
opens the compiler overlay, where the rule was absent. Zero hits for it across
all four react-compiler surfaces before this.
@MajorLift
MajorLift marked this pull request as ready for review September 18, 2026 14:53
@MajorLift MajorLift changed the title feat: Extends performance domain with React Compiler error triage feat: Extends performance domain with React Compiler error triage and coverage antipatterns Sep 18, 2026
@MajorLift
MajorLift enabled auto-merge (squash) September 18, 2026 16:37
@MajorLift
MajorLift merged commit 04242e1 into main Sep 18, 2026
28 checks passed
@MajorLift
MajorLift deleted the jongsun/add/react-compiler-triage branch September 18, 2026 16:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants