Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion reflex/compiler/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ def vite_config_template(
force_full_reload: bool,
experimental_hmr: bool,
sourcemap: bool | Literal["inline", "hidden"],
allowed_hosts: bool | list[str] = False,
):
"""Template for vite.config.js.

Expand All @@ -511,10 +512,17 @@ 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.
allowed_hosts: Allow all hosts (True), specific hosts (list of strings), or only localhost (False).

Returns:
Rendered vite.config.js content as string.
"""
if allowed_hosts is True:
allowed_hosts_line = "\n allowedHosts: true,"
elif isinstance(allowed_hosts, list) and allowed_hosts:
allowed_hosts_line = f"\n allowedHosts: {json.dumps(allowed_hosts)},"
else:
allowed_hosts_line = ""
return rf"""import {{ fileURLToPath, URL }} from "url";
import {{ reactRouter }} from "@react-router/dev/vite";
import {{ defineConfig }} from "vite";
Expand Down Expand Up @@ -586,7 +594,7 @@ def vite_config_template(
hmr: {"true" if experimental_hmr else "false"},
}},
server: {{
port: process.env.PORT,
port: process.env.PORT,{allowed_hosts_line}
hmr: {"true" if hmr else "false"},
watch: {{
ignored: [
Expand Down
5 changes: 5 additions & 0 deletions reflex/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,11 @@ class BaseConfig:
dataclasses.field(default=("*",))
)

# 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.
vite_allowed_hosts: bool | list[str] = False

# Whether to use React strict mode.
react_strict_mode: bool = True

Expand Down
10 changes: 8 additions & 2 deletions reflex/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,8 +243,14 @@ def interpret_env_var_value(
field_type = value_inside_optional(field_type)

if is_union(field_type):
msg = f"Union types are not supported for environment variables: {field_name}."
raise ValueError(msg)
errors = []
for arg in (union_types := get_args(field_type)):
try:
return interpret_env_var_value(value, arg, field_name)
except (ValueError, EnvironmentVarValueError) as e: # noqa: PERF203
errors.append(e)
msg = f"Could not interpret {value!r} for {field_name} as any of {union_types}: {errors}"
raise EnvironmentVarValueError(msg)

value = value.strip()

Expand Down
1 change: 1 addition & 0 deletions reflex/utils/frontend_skeleton.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,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(),
allowed_hosts=config.vite_allowed_hosts,
)


Expand Down
17 changes: 13 additions & 4 deletions tests/units/test_environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,10 +190,19 @@ def test_interpret_enum(self):
result = interpret_env_var_value("value1", _TestEnum, "TEST_FIELD")
assert result == _TestEnum.VALUE1

def test_interpret_union_error(self):
"""Test that union types raise an error."""
with pytest.raises(ValueError, match="Union types are not supported"):
interpret_env_var_value("test", int | str, "TEST_FIELD")
def test_interpret_union_tries_each_type(self):
"""Test that union types try each type in order."""
# str matches first
assert interpret_env_var_value("hello", int | str, "TEST_FIELD") == "hello"
# int matches first
assert interpret_env_var_value("42", int | str, "TEST_FIELD") == 42
# bool matches before str
assert interpret_env_var_value("true", bool | str, "TEST_FIELD") is True

def test_interpret_union_no_match(self):
"""Test that union types raise an error if no type matches."""
with pytest.raises(EnvironmentVarValueError, match="Could not interpret"):
interpret_env_var_value("not_a_number", int | bool, "TEST_FIELD")

def test_interpret_unsupported_type(self):
"""Test unsupported type raises an error."""
Expand Down
Loading