Skip to content

Commit 93b2bc6

Browse files
committed
Revert the move of React Compiler support into a plugin
Reverts 6e6a0bb, f29fb85 and 1ec63f2. The framework has no settled interface for plugins to update the Vite config, so keep the react_compiler config flag for now and move it into a plugin once that interface exists, as suggested in review. Claude-Session: https://claude.ai/code/session_01URTf7ThCUgaCpZGXmgPo7f
1 parent 1ec63f2 commit 93b2bc6

21 files changed

Lines changed: 91 additions & 315 deletions

File tree

‎docs/advanced_onboarding/configuration.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,26 +143,26 @@ See the [plugins reference](/docs/api-reference/plugins/) for the available plug
143143

144144
## React Compiler (Experimental)
145145

146-
React Compiler adds automatic memoization to generated React components. It is disabled by default. To try it, add `ReactCompilerPlugin` to the plugins in `rxconfig.py`:
146+
React Compiler adds automatic memoization to generated React components. It is disabled by default. To try it, set `react_compiler=True` in `rxconfig.py`:
147147

148148
```python
149149
config = rx.Config(
150150
app_name="my_app_name",
151-
plugins=[rx.plugins.ReactCompilerPlugin()],
151+
react_compiler=True,
152152
)
153153
```
154154

155155
Or enable it with an environment variable:
156156

157157
```bash
158-
REFLEX_EXTRA_PLUGINS="reflex.plugins.ReactCompilerPlugin" uv run reflex run
158+
REFLEX_REACT_COMPILER=true uv run reflex run
159159
```
160160

161-
This plugin targets Reflex's supported React 19 runtime and runs in both development and production. It compiles generated JavaScript and JSX in `app/`, `app_components/`, and `utils/components/`. Other runtime utilities and installed dependencies are excluded. Existing Reflex memoization remains enabled.
161+
This option targets Reflex's supported React 19 runtime and runs in both development and production. It compiles generated JavaScript and JSX in `app/`, `app_components/`, and `utils/components/`. Other runtime utilities and installed dependencies are excluded. Existing Reflex memoization remains enabled.
162162

163163
The compiler adds build time and memory overhead. Runtime performance depends on the workload: it can avoid repeated calculations during unrelated state updates, but list-heavy updates can become slower. Measure your application's interactions before enabling it in production.
164164

165-
Restart `reflex run` after adding or removing the plugin, and rebuild production output. Removing it drops the compiler transform and its build dependencies on the next frontend install, unless another plugin requires those dependencies.
165+
Restart `reflex run` after changing the flag, and rebuild production output. Disabling the flag removes the compiler transform and its optional build dependencies on the next frontend install, unless another component or plugin requires those dependencies.
166166

167167
## Customizable App Data Directory
168168

‎docs/api-reference/plugins.md‎

Lines changed: 0 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,6 @@ config = rx.Config(
109109
)
110110
```
111111

112-
### ReactCompilerPlugin
113-
114-
The `ReactCompilerPlugin` compiles generated components with the experimental [React Compiler](https://react.dev/learn/react-compiler), which adds automatic memoization. See [React Compiler](/docs/advanced-onboarding/configuration/#react-compiler-experimental) for its scope and performance tradeoffs.
115-
116-
```python
117-
config = rx.Config(
118-
app_name="my_app",
119-
plugins=[rx.plugins.ReactCompilerPlugin()],
120-
)
121-
```
122-
123112
### TailwindV3Plugin
124113

125114
The `TailwindV3Plugin` integrates Tailwind CSS v3 into your Reflex application. While still supported, TailwindV4Plugin is recommended for new projects.
@@ -214,10 +203,6 @@ class Plugin:
214203
"""Get paths to stylesheets required by the plugin."""
215204
return []
216205

217-
def get_vite_plugins(self, **context) -> Sequence[VitePlugin]:
218-
"""Get Vite plugins to add to the generated vite.config.js."""
219-
return []
220-
221206
def register_route(self, **context) -> None:
222207
"""Contribute pages before the app's first compilation."""
223208
pass
@@ -265,27 +250,6 @@ config = rx.Config(
265250
)
266251
```
267252

268-
### Adding Vite Plugins
269-
270-
A plugin can add [Vite plugins](https://vite.dev/guide/using-plugins) to the generated `vite.config.js` by returning `VitePlugin` entries from `get_vite_plugins`. Each entry imports the module's default export under a name the framework generates, so plugins never clash, and calls it with `args`, a JavaScript source string. `module` is an npm package (declare it as a frontend dependency) or a path relative to `.web`, such as a Vite plugin shipped as a static asset:
271-
272-
```python
273-
from pathlib import Path
274-
275-
from reflex.plugins import Plugin, VitePlugin
276-
277-
278-
class BannerPlugin(Plugin):
279-
def get_static_assets(self, **context):
280-
source = Path(__file__).with_name("vite-plugin-banner.js").read_text()
281-
return [(Path("vite-plugin-banner.js"), source)]
282-
283-
def get_vite_plugins(self, **context):
284-
return [VitePlugin(module="./vite-plugin-banner.js", args='{text: "hi"}')]
285-
```
286-
287-
Vite plugins are placed before React Router's, in plugin configuration order. Set the Vite plugin's `enforce` property to order it relative to Vite's and React Router's own transforms.
288-
289253
### Contributing Pages
290254

291255
A plugin can contribute pages by overriding `register_route`. The hook runs
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Add the experimental `rx.plugins.ReactCompilerPlugin`, which compiles generated components with React Compiler in development and production. Enable it with `plugins=[rx.plugins.ReactCompilerPlugin()]` in `rxconfig.py`.
1+
Add an experimental, default-off `react_compiler` configuration flag to enable React Compiler memoization for generated components in development and production.
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
Add the experimental `ReactCompilerPlugin`, and a `Plugin.get_vite_plugins()` hook that lets plugins add Vite plugins to the generated `vite.config.js` instead of patching its text.
1+
Add the experimental `react_compiler` configuration option, also available as `REFLEX_REACT_COMPILER`, to opt in to automatic React component memoization.

packages/reflex-base/src/reflex_base/plugins/vite-plugin-react-compiler.js renamed to packages/reflex-base/src/reflex_base/.templates/web/vite-plugin-react-compiler.js

File renamed without changes.

‎packages/reflex-base/src/reflex_base/compiler/templates.py‎

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import json
66
import re
7-
from collections.abc import Iterable, Mapping, Sequence
7+
from collections.abc import Iterable, Mapping
88
from typing import TYPE_CHECKING, Any, Literal
99

1010
from reflex_base import constants
@@ -16,7 +16,6 @@
1616
if TYPE_CHECKING:
1717
from reflex.compiler.utils import _ImportDict
1818
from reflex_base.components.component import Component
19-
from reflex_base.plugins.base import VitePlugin
2019

2120

2221
def _sort_hooks(
@@ -735,7 +734,7 @@ def vite_config_template(
735734
allowed_hosts: bool | list[str] = False,
736735
prod_react: bool = False,
737736
warmup_routes: bool = False,
738-
plugins: Sequence[VitePlugin] = (),
737+
react_compiler: bool = False,
739738
):
740739
"""Template for vite.config.js.
741740
@@ -751,7 +750,7 @@ def vite_config_template(
751750
(dev server only; see REFLEX_DEV_PROD_REACT).
752751
warmup_routes: Pre-transform every route module when the dev server
753752
starts, so the first visit to a page does not wait on Vite.
754-
plugins: Vite plugins contributed by Reflex plugins, placed before React Router's.
753+
react_compiler: Enable React Compiler for generated components.
755754
756755
Returns:
757756
Rendered vite.config.js content as string.
@@ -848,19 +847,17 @@ def vite_config_template(
848847
if warmup_routes
849848
else ""
850849
)
851-
plugin_imports = "".join(
852-
f"import reflexVitePlugin{index} from {json.dumps(plugin.module)};\n"
853-
for index, plugin in enumerate(plugins)
854-
)
855-
plugin_calls = "".join(
856-
f" reflexVitePlugin{index}({plugin.args}),\n"
857-
for index, plugin in enumerate(plugins)
850+
react_compiler_import = (
851+
'import reactCompiler from "./vite-plugin-react-compiler.js";\n'
852+
if react_compiler
853+
else ""
858854
)
855+
react_compiler_plugin = " reactCompiler(),\n" if react_compiler else ""
859856
return rf"""import {{ fileURLToPath, URL }} from "url";
860857
import {{ reactRouter }} from "@react-router/dev/vite";
861858
import {{ defineConfig }} from "vite";
862859
import safariCacheBustPlugin from "./vite-plugin-safari-cachebust.js";
863-
{plugin_imports}
860+
{react_compiler_import}
864861
// Ensure that bun always uses the react-dom/server.node functions.
865862
function alwaysUseReactDomServerNode() {{
866863
return {{
@@ -927,7 +924,7 @@ def vite_config_template(
927924
base: "{base}",
928925
plugins: [
929926
alwaysUseReactDomServerNode(),
930-
{plugin_calls} reactRouter(),
927+
{react_compiler_plugin} reactRouter(),
931928
patchReactRouterHmrRuntime(),
932929
safariCacheBustPlugin(),
933930
].concat({"[fullReload()]" if force_full_reload else "[]"}),

‎packages/reflex-base/src/reflex_base/config.py‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ class BaseConfig:
175175
cors_allowed_origins: Comma separated list of origins that are allowed to connect to the backend API.
176176
vite_allowed_hosts: Allowed hosts for the Vite dev server. Set to True to allow all hosts, or provide a list of hostnames (e.g. ["myservice.local"]) to allow specific ones. Prevents 403 errors in Docker, Codespaces, reverse proxies, etc.
177177
react_strict_mode: Whether to use React strict mode.
178+
react_compiler: Enable experimental React Compiler memoization for generated components in development and production. Defaults to False.
178179
frontend_compression_formats: Pre-compressed frontend asset formats to generate for production builds. Supported values are "gzip", "brotli", and "zstd". Use an empty list to disable build-time pre-compression.
179180
frontend_packages: Additional frontend packages to install.
180181
frontend_lazy_bundled_libraries: Load optional dynamic-component libraries when a dynamic component is first evaluated, rather than importing their full namespaces on every page. Defaults to False for compatibility with scripts that read window.__reflex directly.
@@ -237,6 +238,8 @@ class BaseConfig:
237238

238239
react_strict_mode: bool = True
239240

241+
react_compiler: bool = False
242+
240243
frontend_compression_formats: Annotated[
241244
list[str],
242245
SequenceOptions(delimiter=",", strip=True),

‎packages/reflex-base/src/reflex_base/constants/installer.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,12 @@ def DEPENDENCIES(cls) -> dict[str, str]:
162162
"@react-router/fs-routes": _react_router_version,
163163
"vite": "8.3.2",
164164
}
165+
166+
REACT_COMPILER_DEV_DEPENDENCIES = {
167+
"@babel/core": "7.29.7",
168+
"babel-plugin-react-compiler": "1.0.0",
169+
}
170+
165171
# Force specific transitive npm deps to a single resolved version when
166172
# needed. Prefer a `DEV_DEPENDENCIES`/`DEPENDENCIES` pin when the package is
167173
# one we depend on directly: a top-level pin already satisfies and dedupes

‎packages/reflex-base/src/reflex_base/plugins/__init__.py‎

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
base,
1111
compiler,
1212
embed,
13-
react_compiler,
1413
shared_tailwind,
1514
sitemap,
1615
tailwind_v3,
@@ -24,7 +23,6 @@
2423
PostCompileContext,
2524
PreCompileContext,
2625
RegisterRouteContext,
27-
VitePlugin,
2826
get_plugin,
2927
)
3028
from .compiler import (
@@ -36,7 +34,6 @@
3634
PageDefinition,
3735
)
3836
from .embed import EmbedPlugin
39-
from .react_compiler import ReactCompilerPlugin
4037
from .sitemap import SitemapPlugin
4138
from .tailwind_v3 import TailwindV3Plugin
4239
from .tailwind_v4 import TailwindV4Plugin
@@ -54,16 +51,13 @@
5451
"PostBuildContext",
5552
"PostCompileContext",
5653
"PreCompileContext",
57-
"ReactCompilerPlugin",
5854
"RegisterRouteContext",
5955
"SitemapPlugin",
6056
"TailwindV3Plugin",
6157
"TailwindV4Plugin",
62-
"VitePlugin",
6358
"_ScreenshotPlugin",
6459
"embed",
6560
"get_plugin",
66-
"react_compiler",
6761
"sitemap",
6862
"tailwind_v3",
6963
"tailwind_v4",
@@ -74,7 +68,6 @@
7468
"base",
7569
"compiler",
7670
"embed",
77-
"react_compiler",
7871
"shared_tailwind",
7972
"sitemap",
8073
"tailwind_v3",
@@ -90,7 +83,6 @@
9083
"PostCompileContext",
9184
"PreCompileContext",
9285
"RegisterRouteContext",
93-
"VitePlugin",
9486
"get_plugin",
9587
],
9688
"compiler": [
@@ -102,7 +94,6 @@
10294
"PageDefinition",
10395
],
10496
"embed": ["EmbedPlugin"],
105-
"react_compiler": ["ReactCompilerPlugin"],
10697
"sitemap": ["SitemapPlugin"],
10798
"tailwind_v3": ["TailwindV3Plugin"],
10899
"tailwind_v4": ["TailwindV4Plugin"],

‎packages/reflex-base/src/reflex_base/plugins/base.py‎

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"""Base class for all plugins."""
22

3-
import dataclasses
43
from collections.abc import Callable, Mapping, Sequence
54
from enum import Enum
65
from pathlib import Path
@@ -119,21 +118,6 @@ class PostBuildContext(CommonContext):
119118
static_dir: Path
120119

121120

122-
@dataclasses.dataclass(frozen=True, kw_only=True)
123-
class VitePlugin:
124-
"""A Vite plugin added to the generated ``vite.config.js``.
125-
126-
The framework imports the module's default export under a generated name, so
127-
contributions never collide, and calls it with ``args`` in the config's
128-
``plugins`` array.
129-
"""
130-
131-
# Import specifier: an npm package, or a path relative to ``.web``.
132-
module: str
133-
# JavaScript source of the call arguments.
134-
args: str = ""
135-
136-
137121
class Plugin:
138122
"""Base class for all plugins."""
139123

@@ -194,22 +178,6 @@ def get_stylesheet_paths(self, **context: Unpack[CommonContext]) -> Sequence[str
194178
"""
195179
return []
196180

197-
def get_vite_plugins(
198-
self, **context: Unpack[CommonContext]
199-
) -> Sequence[VitePlugin]:
200-
"""Get the Vite plugins to add to the generated ``vite.config.js``.
201-
202-
They are placed before React Router's plugins, in configuration order.
203-
A Vite plugin's ``enforce`` property still orders it among the others.
204-
205-
Args:
206-
context: The context for the plugin.
207-
208-
Returns:
209-
The Vite plugins to add.
210-
"""
211-
return []
212-
213181
def register_route(self, **context: Unpack[RegisterRouteContext]) -> None:
214182
"""Contribute pages before the app's first compilation.
215183

0 commit comments

Comments
 (0)