diff --git a/reflex/compiler/templates.py b/reflex/compiler/templates.py index 0c6b1c90cf8..409ca56c1ba 100644 --- a/reflex/compiler/templates.py +++ b/reflex/compiler/templates.py @@ -4,7 +4,7 @@ import json from collections.abc import Iterable, Mapping -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, Literal from reflex import constants from reflex.constants import Hooks @@ -492,13 +492,21 @@ def package_json_template( }) -def vite_config_template(base: str, hmr: bool, force_full_reload: bool): +def vite_config_template( + base: str, + hmr: bool, + force_full_reload: bool, + experimental_hmr: bool, + sourcemap: bool | Literal["inline", "hidden"], +): """Template for vite.config.js. Args: base: The base path for the Vite config. hmr: Whether to enable hot module replacement. force_full_reload: Whether to force a full reload on changes. + experimental_hmr: Whether to enable experimental HMR features. + sourcemap: The sourcemap configuration. Returns: Rendered vite.config.js content as string. @@ -550,6 +558,7 @@ def vite_config_template(base: str, hmr: bool, force_full_reload: bool): ].concat({"[fullReload()]" if force_full_reload else "[]"}), build: {{ assetsDir: "{base}assets".slice(1), + sourcemap: {"true" if sourcemap is True else "false" if sourcemap is False else repr(sourcemap)}, rollupOptions: {{ onwarn(warning, warn) {{ if (warning.code === "EVAL" && warning.id && warning.id.endsWith("state.js")) return; @@ -570,6 +579,7 @@ def vite_config_template(base: str, hmr: bool, force_full_reload: bool): }}, experimental: {{ enableNativePlugin: false, + hmr: {"true" if experimental_hmr else "false"}, }}, server: {{ port: process.env.PORT, diff --git a/reflex/environment.py b/reflex/environment.py index c9681740a8a..38f99a65f35 100644 --- a/reflex/environment.py +++ b/reflex/environment.py @@ -17,6 +17,7 @@ Annotated, Any, Generic, + Literal, TypeVar, get_args, get_origin, @@ -256,6 +257,27 @@ def interpret_env_var_value( return interpret_existing_path_env(value, field_name) if field_type is Plugin: return interpret_plugin_env(value, field_name) + if get_origin(field_type) is Literal: + literal_values = get_args(field_type) + for literal_value in literal_values: + if isinstance(literal_value, str) and literal_value == value: + return literal_value + if isinstance(literal_value, bool): + try: + interpreted_bool = interpret_boolean_env(value, field_name) + if interpreted_bool == literal_value: + return interpreted_bool + except EnvironmentVarValueError: + continue + if isinstance(literal_value, int): + try: + interpreted_int = interpret_int_env(value, field_name) + if interpreted_int == literal_value: + return interpreted_int + except EnvironmentVarValueError: + continue + msg = f"Invalid literal value: {value!r} for {field_name}, expected one of {literal_values}" + raise EnvironmentVarValueError(msg) if get_origin(field_type) in (list, Sequence): return [ interpret_env_var_value( @@ -687,6 +709,12 @@ class EnvironmentVariables: # Whether to force a full reload on changes. VITE_FORCE_FULL_RELOAD: EnvVar[bool] = env_var(False) + # Whether to enable Rolldown's experimental HMR. + VITE_EXPERIMENTAL_HMR: EnvVar[bool] = env_var(False) + + # Whether to generate sourcemaps for the frontend. + VITE_SOURCEMAP: EnvVar[Literal[False, True, "inline", "hidden"]] = env_var(False) # noqa: RUF038 + # Whether to enable SSR for the frontend. REFLEX_SSR: EnvVar[bool] = env_var(True) diff --git a/reflex/utils/frontend_skeleton.py b/reflex/utils/frontend_skeleton.py index 3ce83142e24..96ced280fe2 100644 --- a/reflex/utils/frontend_skeleton.py +++ b/reflex/utils/frontend_skeleton.py @@ -195,6 +195,8 @@ def _compile_vite_config(config: Config): base=base, hmr=environment.VITE_HMR.get(), force_full_reload=environment.VITE_FORCE_FULL_RELOAD.get(), + experimental_hmr=environment.VITE_EXPERIMENTAL_HMR.get(), + sourcemap=environment.VITE_SOURCEMAP.get(), )