From edbfaa88b5bd760ed3812e3b874e9b10c40bcb79 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Tue, 16 Jun 2026 13:00:32 -0700 Subject: [PATCH 1/5] Add dev-build run mode `reflex run --env dev-build` hot reloads like `dev`, but instead of running the Vite dev server it serves a freshly built (un-minified) frontend bundle mounted into the backend on a single port. Each backend hot reload re-runs the frontend build against the newly compiled output; a manual browser refresh shows changes. This trades the always-on Vite dev server's overhead for cold rebuilds while staying close to dev semantics. To keep rebuilds fast and output debuggable, dev-build disables (overridable): - JS + CSS minification (VITE_MINIFY -> build.minify / build.cssMinify) - autoprefixer (REFLEX_NO_AUTOPREFIXER, read by the generated postcss.config.js) - sourcemaps stay off (the default) Also threads VITE_MINIFY into the vite config, restricts `export --env` to dev/prod, and fixes `run`'s env parsing to honor the new value. --- .../.templates/web/postcss.config.js | 2 +- .../src/reflex_base/compiler/templates.py | 4 + .../src/reflex_base/constants/base.py | 1 + .../src/reflex_base/environment.py | 7 ++ reflex/app.py | 15 +++- reflex/reflex.py | 79 +++++++++++++++++-- reflex/utils/frontend_skeleton.py | 1 + tests/units/utils/test_utils.py | 51 ++++++++++++ 8 files changed, 152 insertions(+), 8 deletions(-) diff --git a/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js b/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js index 3fe1f0379d3..788be5a8679 100644 --- a/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js +++ b/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js @@ -1,6 +1,6 @@ export default { plugins: { "postcss-import": {}, - autoprefixer: {}, + autoprefixer: process.env.REFLEX_NO_AUTOPREFIXER ? false : {}, }, }; diff --git a/packages/reflex-base/src/reflex_base/compiler/templates.py b/packages/reflex-base/src/reflex_base/compiler/templates.py index 0d2f750e9eb..c58749fa2f2 100644 --- a/packages/reflex-base/src/reflex_base/compiler/templates.py +++ b/packages/reflex-base/src/reflex_base/compiler/templates.py @@ -543,6 +543,7 @@ def vite_config_template( force_full_reload: bool, experimental_hmr: bool, sourcemap: bool | Literal["inline", "hidden"], + minify: bool = True, allowed_hosts: bool | list[str] = False, ): """Template for vite.config.js. @@ -553,6 +554,7 @@ def vite_config_template( force_full_reload: Whether to force a full reload on changes. experimental_hmr: Whether to enable experimental HMR features. sourcemap: The sourcemap configuration. + minify: Whether to minify the build output. allowed_hosts: Allow all hosts (True), specific hosts (list of strings), or only localhost (False). Returns: @@ -611,6 +613,8 @@ def vite_config_template( safariCacheBustPlugin(), ].concat({"[fullReload()]" if force_full_reload else "[]"}), build: {{ + minify: {"true" if minify else "false"}, + cssMinify: {"true" if minify else "false"}, sourcemap: {"true" if sourcemap is True else "false" if sourcemap is False else repr(sourcemap)}, rollupOptions: {{ onwarn(warning, warn) {{ diff --git a/packages/reflex-base/src/reflex_base/constants/base.py b/packages/reflex-base/src/reflex_base/constants/base.py index 620d9bd7ee0..94531d86334 100644 --- a/packages/reflex-base/src/reflex_base/constants/base.py +++ b/packages/reflex-base/src/reflex_base/constants/base.py @@ -189,6 +189,7 @@ class Env(str, Enum): """The environment modes.""" DEV = "dev" + DEV_BUILD = "dev-build" PROD = "prod" diff --git a/packages/reflex-base/src/reflex_base/environment.py b/packages/reflex-base/src/reflex_base/environment.py index 99521d1a339..ac4038a3485 100644 --- a/packages/reflex-base/src/reflex_base/environment.py +++ b/packages/reflex-base/src/reflex_base/environment.py @@ -689,6 +689,13 @@ class EnvironmentVariables: # Whether to generate sourcemaps for the frontend. VITE_SOURCEMAP: EnvVar[Literal[False, True, "inline", "hidden"]] = env_var(False) # noqa: RUF038 + # Whether to minify the frontend build output. Disabled by dev-build mode for readable bundles. + VITE_MINIFY: EnvVar[bool] = env_var(True) + + # Read by the generated postcss.config.js to skip autoprefixer. Set by dev-build + # mode to speed up rebuilds (vendor prefixes are unnecessary for local dev). + REFLEX_NO_AUTOPREFIXER: EnvVar[bool] = env_var(False, internal=True) + # Whether to enable SSR for the frontend. REFLEX_SSR: EnvVar[bool] = env_var(True) diff --git a/reflex/app.py b/reflex/app.py index 9c0d2af8db0..92c377b11f5 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -710,11 +710,24 @@ def __call__(self) -> ASGIApp: # rx.asset(shared=True) symlink re-creation doesn't trigger further reloads. remove_stale_external_asset_symlinks() + trigger = get_backend_compile_trigger() self._compile( prerender_routes=should_prerender_routes(), - trigger=get_backend_compile_trigger(), + trigger=trigger, ) + # In dev-build mode the frontend is served as a mounted static bundle rather + # than by the Vite dev server, so each hot reload must re-run the frontend + # build against the freshly compiled output. + if ( + trigger == "hot_reload" + and environment.REFLEX_ENV_MODE.get() == constants.Env.DEV_BUILD + and environment.REFLEX_MOUNT_FRONTEND_COMPILED_APP.get() + ): + from reflex.utils import build + + build.build() + config = get_config() for plugin in config.plugins: diff --git a/reflex/reflex.py b/reflex/reflex.py index 3c340fccea2..feb3a617d04 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -224,6 +224,52 @@ def _run_dev( exec.kill(exec.frontend_process.pid) +def _run_dev_build(running_mode: constants.RunningMode, port: int, host: str): + """Run the app in dev-build mode. + + Like dev mode, but instead of running the Vite dev server it serves a freshly + built (un-minified) frontend bundle mounted into the backend on a single port. + The backend still hot reloads, and each reload re-runs the frontend build + against the newly compiled output, so a manual browser refresh shows changes. + """ + import atexit + + from reflex.utils import build, exec, processes, telemetry + + config = get_config() + + config._set_persistent(frontend_port=port, backend_port=port) + + # Mount the compiled frontend into the dev backend so no Vite server is needed. + environment.REFLEX_MOUNT_FRONTEND_COMPILED_APP.set( + running_mode.has_frontend() and running_mode.has_backend() + ) + + if running_mode.has_frontend(): + # Compile the app and produce the initial frontend build. + _compile_app() + build.setup_frontend_prod(Path.cwd()) + + # Post a telemetry event. + telemetry.send("run-dev") + + # Display custom message when there is a keyboard interrupt. + atexit.register(processes.atexit_handler) + + exec.notify_app_running() + exec.notify_frontend( + f"http://{host}:{port}", + backend_present=running_mode.has_backend(), + ) + + if running_mode.has_backend(): + exec.run_backend( + host, port, config.loglevel.subprocess_level(), running_mode.has_frontend() + ) + else: + exec.run_frontend_prod(host, port) + + def _run_prod(running_mode: constants.RunningMode, port: int, host: str): import atexit @@ -278,12 +324,14 @@ def _run( console.error("Cannot specify --backend-port when not running backend.") raise SystemExit(1) if ( - env == constants.Env.PROD + env in (constants.Env.PROD, constants.Env.DEV_BUILD) and frontend_port and backend_port and frontend_port != backend_port ): - console.error("In production, frontend and backend must run on the same port.") + console.error( + f"In {env.value} mode, frontend and backend must run on the same port." + ) raise SystemExit(1) config = get_config() @@ -293,6 +341,17 @@ def _run( # Set env mode in the environment environment.REFLEX_ENV_MODE.set(env) + # Dev-build serves a real (but readable) frontend bundle: disable JS/CSS + # minification by default for readable output and to speed up rebuilds. + # Sourcemaps are left off (the default) since un-minified output is already + # debuggable, and autoprefixer is skipped (vendor prefixes are unnecessary for + # local dev). All remain overridable via the corresponding env vars. + if env == constants.Env.DEV_BUILD: + if not environment.VITE_MINIFY.is_set(): + environment.VITE_MINIFY.set(False) + if not environment.REFLEX_NO_AUTOPREFIXER.is_set(): + environment.REFLEX_NO_AUTOPREFIXER.set(True) + # Show system info exec.output_system_info() @@ -373,7 +432,10 @@ def _run( auto_increment=requested_port is None, ) - _run_prod(running_mode, port, backend_host) + if env == constants.Env.DEV_BUILD: + _run_dev_build(running_mode, port, backend_host) + else: + _run_prod(running_mode, port, backend_host) @cli.command() @@ -382,7 +444,10 @@ def _run( "--env", type=click.Choice([e.value for e in constants.Env], case_sensitive=False), default=constants.Env.DEV.value, - help="The environment to run the app in.", + help=( + "The environment to run the app in. 'dev-build' hot reloads like 'dev' but " + "serves a freshly built, un-minified frontend bundle instead of the Vite dev server." + ), ) @click.option( "--frontend-only", @@ -464,7 +529,7 @@ def run( running_mode = prerequisites.check_running_mode(frontend_only, backend_only) _run( - env=constants.Env.DEV if env == constants.Env.DEV else constants.Env.PROD, + env=constants.Env(env), running_mode=running_mode, frontend_port=frontend_port, backend_port=backend_port, @@ -538,7 +603,9 @@ def compile(dry: bool, rich: bool): ) @click.option( "--env", - type=click.Choice([e.value for e in constants.Env], case_sensitive=False), + type=click.Choice( + [constants.Env.DEV.value, constants.Env.PROD.value], case_sensitive=False + ), default=constants.Env.PROD.value, help="The environment to export the app in.", ) diff --git a/reflex/utils/frontend_skeleton.py b/reflex/utils/frontend_skeleton.py index 966e14e2686..0bc1e377d5a 100644 --- a/reflex/utils/frontend_skeleton.py +++ b/reflex/utils/frontend_skeleton.py @@ -561,6 +561,7 @@ def _compile_vite_config(config: Config): force_full_reload=environment.VITE_FORCE_FULL_RELOAD.get(), experimental_hmr=environment.VITE_EXPERIMENTAL_HMR.get(), sourcemap=environment.VITE_SOURCEMAP.get(), + minify=environment.VITE_MINIFY.get(), allowed_hosts=config.vite_allowed_hosts, ) diff --git a/tests/units/utils/test_utils.py b/tests/units/utils/test_utils.py index 4c60761e62e..caf2c9a9092 100644 --- a/tests/units/utils/test_utils.py +++ b/tests/units/utils/test_utils.py @@ -815,3 +815,54 @@ def test_is_prod_mode() -> None: assert utils_exec.is_prod_mode() environment.REFLEX_ENV_MODE.set(None) assert not utils_exec.is_prod_mode() + + +def test_dev_build_env_is_not_prod_mode() -> None: + """dev-build is a development mode, so is_prod_mode must stay False.""" + environment.REFLEX_ENV_MODE.set(constants.Env.DEV_BUILD) + try: + assert not utils_exec.is_prod_mode() + finally: + environment.REFLEX_ENV_MODE.set(None) + + +@pytest.mark.parametrize( + ("value", "expected"), + [ + ("dev", constants.Env.DEV), + ("dev-build", constants.Env.DEV_BUILD), + ("prod", constants.Env.PROD), + ], +) +def test_env_enum_roundtrip(value: str, expected: constants.Env) -> None: + """Each env string maps to the matching Env member (used by the run CLI).""" + assert constants.Env(value) is expected + + +@pytest.mark.parametrize("minify", [True, False]) +def test_vite_config_template_minify(minify: bool) -> None: + """The vite config template emits the requested build.minify value.""" + from reflex.compiler import templates as compiler_templates + + config = compiler_templates.vite_config_template( + base="/", + hmr=True, + force_full_reload=False, + experimental_hmr=False, + sourcemap=False, + minify=minify, + ) + expected = "true" if minify else "false" + assert f"minify: {expected}," in config + # CSS minification follows the JS minify flag. + assert f"cssMinify: {expected}," in config + + +@pytest.mark.parametrize("minify", [True, False]) +def test_compile_vite_config_reads_minify_env( + minify: bool, monkeypatch: pytest.MonkeyPatch +) -> None: + """_compile_vite_config threads the VITE_MINIFY env var into the template.""" + monkeypatch.setenv(environment.VITE_MINIFY.name, "true" if minify else "false") + config = frontend_skeleton._compile_vite_config(prerequisites.get_config()) + assert f"minify: {'true' if minify else 'false'}," in config From 0258b0a29fcf0769db801b62ad8fe16d5ec9f0b0 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Tue, 16 Jun 2026 13:37:33 -0700 Subject: [PATCH 2/5] dev-build: address review feedback + add changelog - app.py: guard build.build() on hot reload so a failed frontend build keeps serving the previous build instead of taking the backend down. - postcss.config.js: make REFLEX_NO_AUTOPREFIXER honor falsy values ("false", "0", "") so the override actually works; keep the autoprefixer entry on a single line for the tailwind config rewriters. - Send a distinct "run-dev-build" telemetry event. - Add news fragments for reflex and reflex-base. --- news/6663.feature.md | 1 + packages/reflex-base/news/6663.feature.md | 1 + .../src/reflex_base/.templates/web/postcss.config.js | 4 +++- reflex/app.py | 9 ++++++++- reflex/reflex.py | 2 +- 5 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 news/6663.feature.md create mode 100644 packages/reflex-base/news/6663.feature.md diff --git a/news/6663.feature.md b/news/6663.feature.md new file mode 100644 index 00000000000..e063a6ec5f9 --- /dev/null +++ b/news/6663.feature.md @@ -0,0 +1 @@ +Add a `dev-build` run mode (`reflex run --env dev-build`) that hot reloads like `dev` but serves a freshly built, un-minified frontend bundle mounted into the backend instead of running the Vite dev server. Minification, CSS minification, autoprefixer, and sourcemaps are disabled by default for faster rebuilds and readable output (each overridable via `VITE_MINIFY`, `REFLEX_NO_AUTOPREFIXER`, and `VITE_SOURCEMAP`). diff --git a/packages/reflex-base/news/6663.feature.md b/packages/reflex-base/news/6663.feature.md new file mode 100644 index 00000000000..0d4db46060c --- /dev/null +++ b/packages/reflex-base/news/6663.feature.md @@ -0,0 +1 @@ +Add `Env.DEV_BUILD`, the `VITE_MINIFY` and `REFLEX_NO_AUTOPREFIXER` environment variables, a `minify`/`cssMinify` option on the vite config template, and a `REFLEX_NO_AUTOPREFIXER` toggle in the generated `postcss.config.js` to support the new `dev-build` run mode. diff --git a/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js b/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js index 788be5a8679..98d50061486 100644 --- a/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js +++ b/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js @@ -1,6 +1,8 @@ +const noVendorPrefix = /^(1|true)$/i.test(process.env.REFLEX_NO_AUTOPREFIXER ?? ""); + export default { plugins: { "postcss-import": {}, - autoprefixer: process.env.REFLEX_NO_AUTOPREFIXER ? false : {}, + autoprefixer: noVendorPrefix ? false : {}, }, }; diff --git a/reflex/app.py b/reflex/app.py index 92c377b11f5..22c7bb794e1 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -726,7 +726,14 @@ def __call__(self) -> ASGIApp: ): from reflex.utils import build - build.build() + # A build failure (e.g. a bad import in user code) must not take the + # backend down: keep serving the previous build until the next save. + try: + build.build() + except (Exception, SystemExit) as exc: + console.error( + f"Frontend build failed; serving the previous build. {exc}" + ) config = get_config() diff --git a/reflex/reflex.py b/reflex/reflex.py index feb3a617d04..0e1fe78ca5f 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -251,7 +251,7 @@ def _run_dev_build(running_mode: constants.RunningMode, port: int, host: str): build.setup_frontend_prod(Path.cwd()) # Post a telemetry event. - telemetry.send("run-dev") + telemetry.send("run-dev-build") # Display custom message when there is a keyboard interrupt. atexit.register(processes.atexit_handler) From 96519f5a2ccd2785b09895dd0453f91f22fc43f5 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Tue, 16 Jun 2026 13:40:19 -0700 Subject: [PATCH 3/5] dev-build: apply biome formatting to postcss.config.js template --- .../src/reflex_base/.templates/web/postcss.config.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js b/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js index 98d50061486..407b6f8afaf 100644 --- a/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js +++ b/packages/reflex-base/src/reflex_base/.templates/web/postcss.config.js @@ -1,4 +1,6 @@ -const noVendorPrefix = /^(1|true)$/i.test(process.env.REFLEX_NO_AUTOPREFIXER ?? ""); +const noVendorPrefix = /^(1|true)$/i.test( + process.env.REFLEX_NO_AUTOPREFIXER ?? "", +); export default { plugins: { From 4a391ddf41f52b0470a02dbcd36208e7f11e790a Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Tue, 16 Jun 2026 13:53:20 -0700 Subject: [PATCH 4/5] Rename dev-build mode to preview Per review feedback, align the new run mode's name with the frontend-ecosystem convention (Vite/Next/Nuxt 'preview'). --- news/6663.feature.md | 2 +- packages/reflex-base/news/6663.feature.md | 2 +- .../src/reflex_base/constants/base.py | 2 +- .../reflex-base/src/reflex_base/environment.py | 4 ++-- reflex/app.py | 4 ++-- reflex/reflex.py | 18 +++++++++--------- tests/units/utils/test_utils.py | 8 ++++---- 7 files changed, 20 insertions(+), 20 deletions(-) diff --git a/news/6663.feature.md b/news/6663.feature.md index e063a6ec5f9..896df0a3325 100644 --- a/news/6663.feature.md +++ b/news/6663.feature.md @@ -1 +1 @@ -Add a `dev-build` run mode (`reflex run --env dev-build`) that hot reloads like `dev` but serves a freshly built, un-minified frontend bundle mounted into the backend instead of running the Vite dev server. Minification, CSS minification, autoprefixer, and sourcemaps are disabled by default for faster rebuilds and readable output (each overridable via `VITE_MINIFY`, `REFLEX_NO_AUTOPREFIXER`, and `VITE_SOURCEMAP`). +Add a `preview` run mode (`reflex run --env preview`) that hot reloads like `dev` but serves a freshly built, un-minified frontend bundle mounted into the backend instead of running the Vite dev server. Minification, CSS minification, autoprefixer, and sourcemaps are disabled by default for faster rebuilds and readable output (each overridable via `VITE_MINIFY`, `REFLEX_NO_AUTOPREFIXER`, and `VITE_SOURCEMAP`). diff --git a/packages/reflex-base/news/6663.feature.md b/packages/reflex-base/news/6663.feature.md index 0d4db46060c..b64f11e0e66 100644 --- a/packages/reflex-base/news/6663.feature.md +++ b/packages/reflex-base/news/6663.feature.md @@ -1 +1 @@ -Add `Env.DEV_BUILD`, the `VITE_MINIFY` and `REFLEX_NO_AUTOPREFIXER` environment variables, a `minify`/`cssMinify` option on the vite config template, and a `REFLEX_NO_AUTOPREFIXER` toggle in the generated `postcss.config.js` to support the new `dev-build` run mode. +Add `Env.PREVIEW`, the `VITE_MINIFY` and `REFLEX_NO_AUTOPREFIXER` environment variables, a `minify`/`cssMinify` option on the vite config template, and a `REFLEX_NO_AUTOPREFIXER` toggle in the generated `postcss.config.js` to support the new `preview` run mode. diff --git a/packages/reflex-base/src/reflex_base/constants/base.py b/packages/reflex-base/src/reflex_base/constants/base.py index 94531d86334..7a3f8392b80 100644 --- a/packages/reflex-base/src/reflex_base/constants/base.py +++ b/packages/reflex-base/src/reflex_base/constants/base.py @@ -189,7 +189,7 @@ class Env(str, Enum): """The environment modes.""" DEV = "dev" - DEV_BUILD = "dev-build" + PREVIEW = "preview" PROD = "prod" diff --git a/packages/reflex-base/src/reflex_base/environment.py b/packages/reflex-base/src/reflex_base/environment.py index ac4038a3485..60f88978f53 100644 --- a/packages/reflex-base/src/reflex_base/environment.py +++ b/packages/reflex-base/src/reflex_base/environment.py @@ -689,10 +689,10 @@ class EnvironmentVariables: # Whether to generate sourcemaps for the frontend. VITE_SOURCEMAP: EnvVar[Literal[False, True, "inline", "hidden"]] = env_var(False) # noqa: RUF038 - # Whether to minify the frontend build output. Disabled by dev-build mode for readable bundles. + # Whether to minify the frontend build output. Disabled by preview mode for readable bundles. VITE_MINIFY: EnvVar[bool] = env_var(True) - # Read by the generated postcss.config.js to skip autoprefixer. Set by dev-build + # Read by the generated postcss.config.js to skip autoprefixer. Set by preview # mode to speed up rebuilds (vendor prefixes are unnecessary for local dev). REFLEX_NO_AUTOPREFIXER: EnvVar[bool] = env_var(False, internal=True) diff --git a/reflex/app.py b/reflex/app.py index 22c7bb794e1..87ae16126df 100644 --- a/reflex/app.py +++ b/reflex/app.py @@ -716,12 +716,12 @@ def __call__(self) -> ASGIApp: trigger=trigger, ) - # In dev-build mode the frontend is served as a mounted static bundle rather + # In preview mode the frontend is served as a mounted static bundle rather # than by the Vite dev server, so each hot reload must re-run the frontend # build against the freshly compiled output. if ( trigger == "hot_reload" - and environment.REFLEX_ENV_MODE.get() == constants.Env.DEV_BUILD + and environment.REFLEX_ENV_MODE.get() == constants.Env.PREVIEW and environment.REFLEX_MOUNT_FRONTEND_COMPILED_APP.get() ): from reflex.utils import build diff --git a/reflex/reflex.py b/reflex/reflex.py index 0e1fe78ca5f..2bfc54d9ab5 100644 --- a/reflex/reflex.py +++ b/reflex/reflex.py @@ -224,8 +224,8 @@ def _run_dev( exec.kill(exec.frontend_process.pid) -def _run_dev_build(running_mode: constants.RunningMode, port: int, host: str): - """Run the app in dev-build mode. +def _run_preview(running_mode: constants.RunningMode, port: int, host: str): + """Run the app in preview mode. Like dev mode, but instead of running the Vite dev server it serves a freshly built (un-minified) frontend bundle mounted into the backend on a single port. @@ -251,7 +251,7 @@ def _run_dev_build(running_mode: constants.RunningMode, port: int, host: str): build.setup_frontend_prod(Path.cwd()) # Post a telemetry event. - telemetry.send("run-dev-build") + telemetry.send("run-preview") # Display custom message when there is a keyboard interrupt. atexit.register(processes.atexit_handler) @@ -324,7 +324,7 @@ def _run( console.error("Cannot specify --backend-port when not running backend.") raise SystemExit(1) if ( - env in (constants.Env.PROD, constants.Env.DEV_BUILD) + env in (constants.Env.PROD, constants.Env.PREVIEW) and frontend_port and backend_port and frontend_port != backend_port @@ -341,12 +341,12 @@ def _run( # Set env mode in the environment environment.REFLEX_ENV_MODE.set(env) - # Dev-build serves a real (but readable) frontend bundle: disable JS/CSS + # Preview serves a real (but readable) frontend bundle: disable JS/CSS # minification by default for readable output and to speed up rebuilds. # Sourcemaps are left off (the default) since un-minified output is already # debuggable, and autoprefixer is skipped (vendor prefixes are unnecessary for # local dev). All remain overridable via the corresponding env vars. - if env == constants.Env.DEV_BUILD: + if env == constants.Env.PREVIEW: if not environment.VITE_MINIFY.is_set(): environment.VITE_MINIFY.set(False) if not environment.REFLEX_NO_AUTOPREFIXER.is_set(): @@ -432,8 +432,8 @@ def _run( auto_increment=requested_port is None, ) - if env == constants.Env.DEV_BUILD: - _run_dev_build(running_mode, port, backend_host) + if env == constants.Env.PREVIEW: + _run_preview(running_mode, port, backend_host) else: _run_prod(running_mode, port, backend_host) @@ -445,7 +445,7 @@ def _run( type=click.Choice([e.value for e in constants.Env], case_sensitive=False), default=constants.Env.DEV.value, help=( - "The environment to run the app in. 'dev-build' hot reloads like 'dev' but " + "The environment to run the app in. 'preview' hot reloads like 'dev' but " "serves a freshly built, un-minified frontend bundle instead of the Vite dev server." ), ) diff --git a/tests/units/utils/test_utils.py b/tests/units/utils/test_utils.py index caf2c9a9092..7376b60b618 100644 --- a/tests/units/utils/test_utils.py +++ b/tests/units/utils/test_utils.py @@ -817,9 +817,9 @@ def test_is_prod_mode() -> None: assert not utils_exec.is_prod_mode() -def test_dev_build_env_is_not_prod_mode() -> None: - """dev-build is a development mode, so is_prod_mode must stay False.""" - environment.REFLEX_ENV_MODE.set(constants.Env.DEV_BUILD) +def test_preview_env_is_not_prod_mode() -> None: + """Preview is a development mode, so is_prod_mode must stay False.""" + environment.REFLEX_ENV_MODE.set(constants.Env.PREVIEW) try: assert not utils_exec.is_prod_mode() finally: @@ -830,7 +830,7 @@ def test_dev_build_env_is_not_prod_mode() -> None: ("value", "expected"), [ ("dev", constants.Env.DEV), - ("dev-build", constants.Env.DEV_BUILD), + ("preview", constants.Env.PREVIEW), ("prod", constants.Env.PROD), ], ) From ff68e206158182fb788175aba72acfb05ca297b4 Mon Sep 17 00:00:00 2001 From: Khaleel Al-Adhami Date: Tue, 16 Jun 2026 14:11:57 -0700 Subject: [PATCH 5/5] preview: drop internal=True on REFLEX_NO_AUTOPREFIXER so the name matches what postcss.config.js reads --- packages/reflex-base/src/reflex_base/environment.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/reflex-base/src/reflex_base/environment.py b/packages/reflex-base/src/reflex_base/environment.py index 60f88978f53..7ca79e7c097 100644 --- a/packages/reflex-base/src/reflex_base/environment.py +++ b/packages/reflex-base/src/reflex_base/environment.py @@ -692,9 +692,8 @@ class EnvironmentVariables: # Whether to minify the frontend build output. Disabled by preview mode for readable bundles. VITE_MINIFY: EnvVar[bool] = env_var(True) - # Read by the generated postcss.config.js to skip autoprefixer. Set by preview - # mode to speed up rebuilds (vendor prefixes are unnecessary for local dev). - REFLEX_NO_AUTOPREFIXER: EnvVar[bool] = env_var(False, internal=True) + # Read by the generated postcss.config.js to skip autoprefixer in preview mode. + REFLEX_NO_AUTOPREFIXER: EnvVar[bool] = env_var(False) # Whether to enable SSR for the frontend. REFLEX_SSR: EnvVar[bool] = env_var(True)