Skip to content

ENG-12682 Let React Compiler optimize generated components - #7694

Open
FarhanAliRaza wants to merge 3 commits into
mainfrom
farhan/react-compiler-generation-revive
Open

FarhanAliRaza wants to merge 3 commits into
mainfrom
farhan/react-compiler-generation-revive

Conversation

@FarhanAliRaza

@FarhanAliRaza FarhanAliRaza commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Supersedes #7272. That PR was stacked on #7234 and auto-closed, unmerged, when its base branch was deleted after #7234 merged. This PR replays its changes onto current main: the diff between the base-branch head it last merged (07aa53cb6) and its head (4f3e5dbba). Farhan is the commit author.

All Submissions:

  • Have you followed the guidelines stated in CONTRIBUTING.md file?
  • Have you checked to ensure there aren't any other open Pull Requests for the desired changed?

Type of change

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update (included: docs/advanced_onboarding/configuration.md)

Changes

React Compiler bailed out on most generated pages and memo wrappers because of patterns Reflex emits. This PR changes those patterns. It also adds an auto_memoize option, so an app using react_compiler can let the compiler memoize whole pages instead of Reflex's generated memo wrappers.

Bailout Fix
refs["ref_x"] = ref_x during render ("This value cannot be modified") const ref_x = useRegisteredRef("ref_x"). The hook lives in utils/state.js, outside compiler scope, and keeps the same registry behavior.
useMemo(generateUUID, []) ("Expected the first argument to be an inline function expression") useMemo(() => generateUUID(), [])
useCallback deps list addEvents, ReflexEvent, and unused hook bindings such as setFilesById ("Found extra memoization dependencies") Only bindings the callback references
Capture-free (...args) => addEvents(...) handlers crash function outlining ("Expected temporaries to be promoted") enableFunctionOutlining: false
jsx(type, props, ...children) from Emotion is an unknown function, so compiled pages cannot cache elements moduleTypeProvider describing jsx like JSX syntax: frozen arguments, frozen result

The experimental compiler (0.0.0-experimental-a1856f3-20260507) is required, because 1.0.0 still rejects refs passed to jsx() and optional calls in ternary tests. This is still npm's current experimental tag, and REACT_COMPILER_DEV_DEPENDENCIES is the only pin; @babel/core stays at main's 7.29.7.

auto_memoize=False removes MemoizeStatefulPlugin from page compilation. App-root memoization (_memoize_app_root) is unchanged.

Conflicts with main and how they were resolved

The patch applied cleanly everywhere except two hunks:

I also checked the memo-compiler changes on main that the patch didn't textually touch: mirrored memo modules, auto-memo keying in memoize.py, and compiler.py. default_page_plugins is still the only place page compilation adds MemoizeStatefulPlugin, so the auto_memoize switch still covers every page path.

Measurements (from the original PR #7272)

Production builds, Chromium, direct state dispatch, 11 alternating rounds × 100 updates. Dashboard page: sidebar, 8 KPI cards, two Recharts charts, tabs with a form and a 10-item list, static cards.

Update Today react_compiler react_compiler + auto_memoize=False
One KPI value 0.87 ms, 171 renders 0.095 ms, 28 renders 0.106 ms, 10 renders
Search input 0.99 ms 0.144 ms 0.163 ms
Chart data 5.90 ms 5.19 ms 5.06 ms
Activity list 0.89 ms 0.33 ms 0.42 ms
Header select 1.06 ms 0.27 ms 0.30 ms

Python compile time with auto-memo off (from #7272):

App Auto-memo on Auto-memo off
Dashboard fixture 200 ms 128 ms
Feature fixture 179 ms 144 ms
Docs site 42.2 s 31.7 s

Testing

  • uv run ruff check ., uv run ruff format ., uv run pyright reflex tests (0 errors), and uv run pre-commit run --all-files all pass. The .pyi hook made no changes.
  • tests/units/compiler, tests/units/reflex_base, test_prerequisites.py, test_config.py, and components/test_component.py: 1943 passed.
  • Full unit suite: 15274 passed. The only failures were the 14 reflex_bench/drivers/test_browser.py tests, because the dev container lacks the Playwright headless-shell binary those tests need. That is unrelated to this diff.
  • Smoke app with react_compiler=True, auto_memoize=False under reflex run --env prod:
    • It compiles and builds, with no memo wrappers generated.
    • The page chunk is compiler-transformed (memo cache sentinels are present).
    • In Chromium, three backend increments, rx.set_focus through useRegisteredRef, and a controlled-input round trip all worked, with no page errors.

Known limits (from #7272)

  • With auto_memoize=False, a page the compiler skips re-renders fully on every state change, about 2× slower than today. The docs say to measure before turning it off.
  • Custom components that inject raw hook JavaScript can still cause bailouts.

https://claude.ai/code/session_01LwJUCTv3FVWzi1UoUpyMLT


Generated by Claude Code

View guided diff Turn on auto-fix

Replays #7272 onto main. That PR auto-closed when its base branch was
deleted after #7234 merged; its own changes were the diff between the
base-branch head it last merged (07aa53c) and its head (4f3e5db),
covering commits c01f4d4, 755ddba and 4f3e5db.

Change the patterns Reflex emits that made React Compiler bail out:
register refs through a useRegisteredRef hook instead of writing to
refs during render, wrap generateUUID in an inline useMemo callback,
list only referenced bindings as useCallback dependencies, disable
function outlining, and describe Emotion's jsx() to the compiler as
JSX. Pin the experimental compiler, which accepts refs passed to jsx().

Add an auto_memoize config option (default True). False removes
MemoizeStatefulPlugin from page compilation so the compiler memoizes
whole pages; app-root memoization is unchanged.

Conflicts with main: #7586 removed hook positions, so the ref hook no
longer passes VarData(position=INTERNAL); #7435 removed
backend_state_mismatch from state.js, so it stays removed.

Claude-Session: https://claude.ai/code/session_01LwJUCTv3FVWzi1UoUpyMLT
@FarhanAliRaza
FarhanAliRaza requested a review from Alek99 October 29, 2026 16:44
@FarhanAliRaza
FarhanAliRaza requested a review from a team as a code owner October 29, 2026 16:44
@linear-code

linear-code Bot commented Oct 29, 2026

Copy link
Copy Markdown

ENG-12682

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

All reported issues were addressed across 20 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread tests/units/compiler/test_plugins.py Resolved
@greptile-apps

greptile-apps Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; no blocking issues were found.

Summary

This PR lets React Compiler optimize more generated components and adds auto_memoize=False for apps that want the compiler to optimize whole pages.

  • React Compiler can optimize more generated Reflex components.
  • App developers can let React Compiler replace page memo wrappers.

No actionable new issues were found. No previous review threads were supplied.

Reviews (2) · Last reviewed commit: "Run the auto_memoize compile_app test as..." · Reviewed by Greptile

@codspeed

codspeed Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

1 warning

⚠️ 22 benchmarks are dominated by system calls

System calls cannot be simulated consistently and are left out of the measure. The reported value understates the real cost. Switch to the Walltime instrument to measure them.

Learn more about system calls

See affected benchmarks

✅ 148 untouched benchmarks


Comparing farhan/react-compiler-generation-revive (2ee7672) with main (58d798f)

Open in CodSpeed

@masenf masenf added the on deck PRs lined up to review / merge next label Oct 30, 2026
Export GENERATED_EVENT_CALLBACK from the React Compiler adapter and test it
against the names get_memoized_event_triggers produces, so a rename on either
side fails a test instead of silently restoring compiler bailouts.

Drop the Unicode stale-callback claim from the reflex-base fragment: main never
had that bug. Move inline test imports to module level.
Without dry_run, REFLEX_SKIP_COMPILE or a leftover .web/nocompile file made
compile_app return before building the page plugins, and the test wrote into
the working directory's .web.
@masenf masenf added documentation Improvements or additions to documentation perf Performance-improving changes labels Nov 2, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation on deck PRs lined up to review / merge next perf Performance-improving changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants