perf(theme): add React Compiler support for automatic memoization & performance optimization 🚀 - #3586
Conversation
…d third-party script loading
Updated rspress-plugin-third-parties description to include Twitter/X as a supported embed, enhancing its utility for users.
…ant state initialization
|
To provide additional context on why shipping React Compiler with Rspress is a safe and high-impact improvement, here is how other major production applications and libraries have benefited from it: 📊 Real-World Production Benchmarks
💡 Key Takeaways Beyond Performance
Integrating this into Rspress gives our documentation users these exact out-of-the-box rendering gains without requiring any manual setup on their end. |
|
|
||
| // TODO: fallback should be a loading spinner | ||
| export const Content = ({ fallback = <></> }: { fallback?: ReactNode }) => { | ||
| export const Content = ({ |
There was a problem hiding this comment.
This change was made to fix the following error from react-compiler.
(BuildHIR::node.lowerReorderableExpression)Expression typeJSXFragmentcannot be safely reordered.
|
|
||
| const Pre = useMemo(() => { | ||
| return getCustomMDXComponent().pre; | ||
| }, [getCustomMDXComponent]); |
There was a problem hiding this comment.
This change was made to fix the following error, which is a stable external function getCustomMDXComponent.
Found 1 error:
Error: Found extra memoization dependencies
Extra dependencies can cause a value to update more often than it should, resulting in performance problems such as excessive renders or effects firing too often.
|
|
||
| const defaultValueIndex = | ||
| defaultValue !== undefined | ||
| ? tabValues.findIndex(item => item.value === defaultValue) |
There was a problem hiding this comment.
Move the calling of React hook top to resolve the React compiler error and to maintain React standards:
Error: Hooks must always be called in a consistent order, and may not be called conditionally. See the Rules of Hooks (https://react.dev/warnings/invalid-hook-call-warning)
|
Thanks for taking the time to contribute this to Rspress. However, benchmarks from other products do not demonstrate that this change provides a meaningful benefit to Rspress. This PR adds a runtime dependency, changes the build pipeline, and requires source refactors, so I think it needs Rspress-specific evidence to justify the trade-off. Could you provide before-and-after measurements on representative Rspress sites and interactions—for example, render counts, INP or frame time, bundle size, and build time—and identify the concrete bottlenecks this PR improves? Without that data, I don't think we have enough evidence to merge this change. |
|
Bundle size comparison https://github.com/web-infra-dev/rspress/actions/runs/31038294665?pr=3586#summary-92540812580
These bundle size changes are within an acceptable range. |
|
Hi @SoonIter, Extremely sorry for the delay! Here is the benchmark comparison and analysis I gathered from the React DevTools Profiler with screenshot proof. 1.
|
Dropping it to ~1.8ms leaves plenty of room on the main thread for layout and paint. |
|
Added the profiler benchmark above (~85% drop in render time on search/tab updates). Alternatively, if we want to keep the code cleaner, we can opt into React Compiler with "use memo" annotation mode for these specific components. Happy to adjust either way :) |






📝 Summary
This PR integrates the React Compiler into Rspress core/theme packages following the React team's official guidance for shipping compiled libraries.
By pre-compiling Rspress components at build time:
react-compiler-runtimeto seamlessly support both React 18 and React 19.🔍 Motivation & Problem Statement
Currently, the Rspress codebase relies heavily on manual optimization (
useMemo,useCallback,React.memo), leading to missing memoization in several key UI components.Key Issues Observed:
useMemo/useCallbackis error-prone and adds boilerplate.💡 Examples in Current Codebase
1. Object recreation & manual hook wrapping:
PackageManagerTabs/index.tsxOn every render pass,
packageMangerToIconis recreated and mutated, whilePrerelies on explicituseMemo:With React Compiler: The compiler automatically caches dynamic element maps and component references at build time.
2. Static / Pure UI Components:
Badge/index.tsxPure components like
Badgeexecute and re-render every time parent context/state changes:With React Compiler: Render outputs are automatically memoized without needing to wrap every UI component in
React.memo.🛠️ Implementation Details (React Compiler Library Setup)
Following the React team's official recommendations for library authors:
babel-plugin-react-compileras a dev dependency to handle build-time compilation.react-compiler-runtimeas a direct dependency inpackage.jsonto handle runtime auto-memoization hooks across versions:{ "dependencies": { "react-compiler-runtime": "^1.0.0" } }target: '18') to maintain full backward compatibility for React 18 and React 19 users.🚀 Performance Impact
useMemo/useCallback/React.memofor component-level performance gains.