reflex 0.8.13a1__py3-none-any.whl → 0.8.14a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of reflex might be problematic. Click here for more details.

@@ -6,7 +6,6 @@
6
6
  from collections.abc import Mapping, Sequence
7
7
  from typing import Any
8
8
 
9
- import reflex
10
9
  from reflex.components.core.breakpoints import Breakpoints
11
10
  from reflex.components.react_player.react_player import ReactPlayer
12
11
  from reflex.event import EventType, PointerEventInfo
@@ -17,13 +16,18 @@ class Video(ReactPlayer):
17
16
  def create(
18
17
  cls,
19
18
  *children,
20
- url: Var[str] | str | None = None,
19
+ src: Var[list[dict[str, str]] | list[str] | str]
20
+ | list[dict[str, str]]
21
+ | list[str]
22
+ | str
23
+ | None = None,
21
24
  playing: Var[bool] | bool | None = None,
22
25
  loop: Var[bool] | bool | None = None,
23
26
  controls: Var[bool] | bool | None = None,
24
27
  light: Var[bool] | bool | None = None,
25
28
  volume: Var[float] | float | None = None,
26
29
  muted: Var[bool] | bool | None = None,
30
+ config: Var[dict[str, Any]] | dict[str, Any] | None = None,
27
31
  style: Sequence[Mapping[str, Any]]
28
32
  | Mapping[str, Any]
29
33
  | Var[Mapping[str, Any]]
@@ -35,18 +39,16 @@ class Video(ReactPlayer):
35
39
  class_name: Any | None = None,
36
40
  custom_attrs: dict[str, Var | Any] | None = None,
37
41
  on_blur: EventType[()] | None = None,
38
- on_buffer: EventType[()] | None = None,
39
- on_buffer_end: EventType[()] | None = None,
40
42
  on_click: EventType[()] | EventType[PointerEventInfo] | None = None,
41
43
  on_click_preview: EventType[()] | None = None,
42
44
  on_context_menu: EventType[()] | EventType[PointerEventInfo] | None = None,
43
- on_disable_pip: EventType[()] | None = None,
44
45
  on_double_click: EventType[()] | EventType[PointerEventInfo] | None = None,
45
- on_duration: EventType[()] | EventType[float] | None = None,
46
- on_enable_pip: EventType[()] | None = None,
46
+ on_duration_change: EventType[Any] | None = None,
47
47
  on_ended: EventType[()] | None = None,
48
+ on_enter_picture_in_picture: EventType[()] | None = None,
48
49
  on_error: EventType[()] | None = None,
49
50
  on_focus: EventType[()] | None = None,
51
+ on_leave_picture_in_picture: EventType[()] | None = None,
50
52
  on_mount: EventType[()] | None = None,
51
53
  on_mouse_down: EventType[()] | None = None,
52
54
  on_mouse_enter: EventType[()] | None = None,
@@ -57,54 +59,29 @@ class Video(ReactPlayer):
57
59
  on_mouse_up: EventType[()] | None = None,
58
60
  on_pause: EventType[()] | None = None,
59
61
  on_play: EventType[()] | None = None,
60
- on_playback_quality_change: EventType[()] | None = None,
61
- on_playback_rate_change: EventType[()] | None = None,
62
- on_progress: EventType[()]
63
- | EventType[reflex.components.react_player.react_player.Progress]
64
- | None = None,
62
+ on_playing: EventType[()] | None = None,
63
+ on_progress: EventType[Any] | None = None,
64
+ on_rate_change: EventType[Any] | None = None,
65
65
  on_ready: EventType[()] | None = None,
66
66
  on_scroll: EventType[()] | None = None,
67
67
  on_scroll_end: EventType[()] | None = None,
68
- on_seek: EventType[()] | EventType[float] | None = None,
68
+ on_seeked: EventType[Any] | None = None,
69
+ on_seeking: EventType[()] | None = None,
69
70
  on_start: EventType[()] | None = None,
71
+ on_time_update: EventType[Any] | None = None,
70
72
  on_unmount: EventType[()] | None = None,
73
+ on_waiting: EventType[()] | None = None,
71
74
  **props,
72
75
  ) -> Video:
73
- """Create the component.
76
+ """Create a component.
74
77
 
75
78
  Args:
76
- *children: The children of the component.
77
- url: The url of a video or song to play
78
- playing: Set to true or false to pause or play the media
79
- loop: Set to true or false to loop the media
80
- controls: Set to true or false to display native player controls.
81
- light: Set to true to show just the video thumbnail, which loads the full player on click
82
- volume: Set the volume of the player, between 0 and 1
83
- muted: Mutes the player
84
- on_ready: Called when media is loaded and ready to play. If playing is set to true, media will play immediately.
85
- on_start: Called when media starts playing.
86
- on_play: Called when media starts or resumes playing after pausing or buffering.
87
- on_progress: Callback containing played and loaded progress as a fraction, and playedSeconds and loadedSeconds in seconds. eg { played: 0.12, playedSeconds: 11.3, loaded: 0.34, loadedSeconds: 16.7 }
88
- on_duration: Callback containing duration of the media, in seconds.
89
- on_pause: Called when media is paused.
90
- on_buffer: Called when media starts buffering.
91
- on_buffer_end: Called when media has finished buffering. Works for files, YouTube and Facebook.
92
- on_seek: Called when media seeks with seconds parameter.
93
- on_playback_rate_change: Called when playback rate of the player changed. Only supported by YouTube, Vimeo (if enabled), Wistia, and file paths.
94
- on_playback_quality_change: Called when playback quality of the player changed. Only supported by YouTube (if enabled).
95
- on_ended: Called when media finishes playing. Does not fire when loop is set to true.
96
- on_error: Called when an error occurs whilst attempting to play media.
97
- on_click_preview: Called when user clicks the light mode preview.
98
- on_enable_pip: Called when picture-in-picture mode is enabled.
99
- on_disable_pip: Called when picture-in-picture mode is disabled.
100
- style: The style of the component.
101
- key: A unique key for the component.
102
- id: The id for the component.
103
- ref: The Var to pass as the ref to the component.
104
- class_name: The class name for the component.
105
- custom_attrs: custom attribute
106
- **props: The props of the component.
79
+ children: The children of the component.
80
+ props: The props of the component.
107
81
 
108
82
  Returns:
109
- The component.
83
+ The created component.
84
+
85
+ Raises:
86
+ ValueError: If both a deprecated prop and its replacement are both passed.
110
87
  """
@@ -96,6 +96,4 @@ class Color:
96
96
  Returns:
97
97
  The formatted color.
98
98
  """
99
- from reflex.vars import LiteralColorVar
100
-
101
- return LiteralColorVar.create(self).__format__(format_spec)
99
+ return format_color(self.color, self.shade, self.alpha)
@@ -14,7 +14,7 @@ class Bun(SimpleNamespace):
14
14
  """Bun constants."""
15
15
 
16
16
  # The Bun version.
17
- VERSION = "1.2.22"
17
+ VERSION = "1.2.23"
18
18
 
19
19
  # Min Bun Version
20
20
  MIN_VERSION = "1.2.17"
@@ -75,7 +75,7 @@ fetch-retries=0
75
75
 
76
76
 
77
77
  def _determine_react_router_version() -> str:
78
- default_version = "7.9.1"
78
+ default_version = "7.9.3"
79
79
  if (version := os.getenv("REACT_ROUTER_VERSION")) and version != default_version:
80
80
  from reflex.utils import console
81
81
 
@@ -131,7 +131,7 @@ class PackageJson(SimpleNamespace):
131
131
  "react": cls._react_version,
132
132
  "react-helmet": "6.1.0",
133
133
  "react-dom": cls._react_version,
134
- "isbot": "5.1.30",
134
+ "isbot": "5.1.31",
135
135
  "socket.io-client": "4.8.1",
136
136
  "universal-cookie": "7.2.2",
137
137
  }
@@ -143,11 +143,11 @@ class PackageJson(SimpleNamespace):
143
143
  "postcss-import": "16.1.1",
144
144
  "@react-router/dev": _react_router_version,
145
145
  "@react-router/fs-routes": _react_router_version,
146
- "vite": "npm:rolldown-vite@7.1.12",
146
+ "vite": "npm:rolldown-vite@7.1.13",
147
147
  }
148
148
  OVERRIDES = {
149
149
  # This should always match the `react` version in DEPENDENCIES for recharts compatibility.
150
150
  "react-is": _react_version,
151
151
  "cookie": "1.0.2",
152
- "vite": "npm:rolldown-vite@7.1.12",
152
+ "vite": "npm:rolldown-vite@7.1.13",
153
153
  }
@@ -359,7 +359,7 @@ def _get_default_library_name_parts() -> list[str]:
359
359
  """Get the default library name. Based on the current directory name, remove any non-alphanumeric characters.
360
360
 
361
361
  Raises:
362
- Exit: If the current directory name is not suitable for python projects, and we cannot find a valid library name based off it.
362
+ SystemExit: If the current directory name is not suitable for python projects, and we cannot find a valid library name based off it.
363
363
 
364
364
  Returns:
365
365
  The parts of default library name.
@@ -377,13 +377,13 @@ def _get_default_library_name_parts() -> list[str]:
377
377
  console.error(
378
378
  f"Based on current directory name {current_dir_name}, the library name is {constants.Reflex.MODULE_NAME}. This package already exists. Please use --library-name to specify a different name."
379
379
  )
380
- raise click.exceptions.Exit(code=1)
380
+ raise SystemExit(1)
381
381
  if not parts:
382
382
  # The folder likely has a name not suitable for python paths.
383
383
  console.error(
384
384
  f"Could not find a valid library name based on the current directory: got {current_dir_name}."
385
385
  )
386
- raise click.exceptions.Exit(code=1)
386
+ raise SystemExit(1)
387
387
  return parts
388
388
 
389
389
 
@@ -408,7 +408,7 @@ def _validate_library_name(library_name: str | None) -> NameVariants:
408
408
  library_name: The name of the library if picked otherwise None.
409
409
 
410
410
  Raises:
411
- Exit: If the library name is not suitable for python projects.
411
+ SystemExit: If the library name is not suitable for python projects.
412
412
 
413
413
  Returns:
414
414
  A tuple containing the various names such as package name, class name, etc., needed for the project.
@@ -419,7 +419,7 @@ def _validate_library_name(library_name: str | None) -> NameVariants:
419
419
  console.error(
420
420
  f"Please use only alphanumeric characters or dashes: got {library_name}"
421
421
  )
422
- raise click.exceptions.Exit(code=1)
422
+ raise SystemExit(1)
423
423
 
424
424
  # If not specified, use the current directory name to form the module name.
425
425
  name_parts = (
@@ -513,13 +513,13 @@ def init(
513
513
  install: Whether to install package from this local custom component in editable mode.
514
514
 
515
515
  Raises:
516
- Exit: If the pyproject.toml already exists.
516
+ SystemExit: If the pyproject.toml already exists.
517
517
  """
518
518
  from reflex.utils import exec
519
519
 
520
520
  if CustomComponents.PYPROJECT_TOML.exists():
521
521
  console.error(f"A {CustomComponents.PYPROJECT_TOML} already exists. Aborting.")
522
- click.exceptions.Exit(code=1)
522
+ raise SystemExit(1)
523
523
 
524
524
  # Show system info.
525
525
  exec.output_system_info()
@@ -544,7 +544,7 @@ def init(
544
544
  if _pip_install_on_demand(package_name=".", install_args=["-e"]):
545
545
  console.info(f"Package {package_name} installed!")
546
546
  else:
547
- raise click.exceptions.Exit(code=1)
547
+ raise SystemExit(1)
548
548
 
549
549
  console.print("[bold]Custom component initialized successfully!")
550
550
  console.rule("[bold]Project Summary")
@@ -627,7 +627,7 @@ def _run_build():
627
627
  """Run the build command.
628
628
 
629
629
  Raises:
630
- Exit: If the build fails.
630
+ SystemExit: If the build fails.
631
631
  """
632
632
  console.print("Building custom component...")
633
633
 
@@ -637,7 +637,7 @@ def _run_build():
637
637
  if _run_commands_in_subprocess(cmds):
638
638
  console.info("Custom component built successfully!")
639
639
  else:
640
- raise click.exceptions.Exit(code=1)
640
+ raise SystemExit(1)
641
641
 
642
642
 
643
643
  @custom_components_cli.command(name="build")
@@ -651,7 +651,7 @@ def _collect_details_for_gallery():
651
651
  """Helper to collect details on the custom component to be included in the gallery.
652
652
 
653
653
  Raises:
654
- Exit: If pyproject.toml file is ill-formed or the request to the backend services fails.
654
+ SystemExit: If pyproject.toml file is ill-formed or the request to the backend services fails.
655
655
  """
656
656
  import httpx
657
657
  from reflex_cli.utils import hosting
@@ -664,7 +664,7 @@ def _collect_details_for_gallery():
664
664
  console.error(
665
665
  "Unable to authenticate with Reflex backend services. Make sure you are logged in."
666
666
  )
667
- raise click.exceptions.Exit(code=1)
667
+ raise SystemExit(1)
668
668
 
669
669
  console.rule("[bold]Custom Component Information")
670
670
  params = {}
@@ -694,11 +694,11 @@ def _collect_details_for_gallery():
694
694
  console.error(
695
695
  f"{package_name} is owned by another user. Unable to update the information for it."
696
696
  )
697
- raise click.exceptions.Exit(code=1)
697
+ raise SystemExit(1)
698
698
  response.raise_for_status()
699
699
  except httpx.HTTPError as he:
700
700
  console.error(f"Unable to complete request due to {he}.")
701
- raise click.exceptions.Exit(code=1) from he
701
+ raise SystemExit(1) from None
702
702
 
703
703
  files = []
704
704
  if (image_file_and_extension := _get_file_from_prompt_in_loop()) is not None:
@@ -733,7 +733,7 @@ def _collect_details_for_gallery():
733
733
 
734
734
  except httpx.HTTPError as he:
735
735
  console.error(f"Unable to complete request due to {he}.")
736
- raise click.exceptions.Exit(code=1) from he
736
+ raise SystemExit(1) from None
737
737
 
738
738
  console.info("Custom component information successfully shared!")
739
739
 
@@ -769,7 +769,7 @@ def _get_file_from_prompt_in_loop() -> tuple[bytes, str] | None:
769
769
  image_file = image_file_path.read_bytes()
770
770
  except OSError as ose:
771
771
  console.error(f"Unable to read the {file_extension} file due to {ose}")
772
- raise click.exceptions.Exit(code=1) from ose
772
+ raise SystemExit(1) from None
773
773
  else:
774
774
  return image_file, file_extension
775
775
 
@@ -790,9 +790,9 @@ def install():
790
790
  """Install package from this local custom component in editable mode.
791
791
 
792
792
  Raises:
793
- Exit: If unable to install the current directory in editable mode.
793
+ SystemExit: If unable to install the current directory in editable mode.
794
794
  """
795
795
  if _pip_install_on_demand(package_name=".", install_args=["-e"]):
796
796
  console.info("Package installed successfully!")
797
797
  else:
798
- raise click.exceptions.Exit(code=1)
798
+ raise SystemExit(1)
reflex/environment.py CHANGED
@@ -660,6 +660,9 @@ class EnvironmentVariables:
660
660
  # Whether to enable SSR for the frontend.
661
661
  REFLEX_SSR: EnvVar[bool] = env_var(True)
662
662
 
663
+ # Whether to mount the compiled frontend app in the backend server in production.
664
+ REFLEX_MOUNT_FRONTEND_COMPILED_APP: EnvVar[bool] = env_var(False, internal=True)
665
+
663
666
 
664
667
  environment = EnvironmentVariables()
665
668
 
@@ -179,7 +179,7 @@ class TailwindPlugin(PluginBase):
179
179
  config: TailwindConfig = dataclasses.field(
180
180
  default_factory=lambda: TailwindConfig(
181
181
  plugins=[
182
- "@tailwindcss/typography@0.5.18",
182
+ "@tailwindcss/typography@0.5.19",
183
183
  ],
184
184
  )
185
185
  )
reflex/reflex.py CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import atexit
6
5
  from importlib.util import find_spec
7
6
  from pathlib import Path
8
7
  from typing import TYPE_CHECKING
@@ -132,8 +131,11 @@ def _run(
132
131
  frontend_port: int | None = None,
133
132
  backend_port: int | None = None,
134
133
  backend_host: str | None = None,
134
+ single_port: bool = False,
135
135
  ):
136
136
  """Run the app in the given directory."""
137
+ import atexit
138
+
137
139
  from reflex.utils import build, exec, prerequisites, processes
138
140
 
139
141
  config = get_config()
@@ -173,7 +175,9 @@ def _run(
173
175
  auto_increment=auto_increment_frontend,
174
176
  )
175
177
 
176
- if backend:
178
+ if single_port:
179
+ backend_port = frontend_port
180
+ elif backend:
177
181
  auto_increment_backend = not bool(backend_port or config.backend_port)
178
182
 
179
183
  backend_port = processes.handle_port(
@@ -223,23 +227,23 @@ def _run(
223
227
  if not return_result:
224
228
  raise SystemExit(1)
225
229
 
230
+ if env != constants.Env.PROD and env != constants.Env.DEV:
231
+ msg = f"Invalid env: {env}. Must be DEV or PROD."
232
+ raise ValueError(msg)
233
+
226
234
  # Get the frontend and backend commands, based on the environment.
227
- setup_frontend = frontend_cmd = backend_cmd = None
228
235
  if env == constants.Env.DEV:
229
236
  setup_frontend, frontend_cmd, backend_cmd = (
230
237
  build.setup_frontend,
231
238
  exec.run_frontend,
232
239
  exec.run_backend,
233
240
  )
234
- if env == constants.Env.PROD:
241
+ elif env == constants.Env.PROD:
235
242
  setup_frontend, frontend_cmd, backend_cmd = (
236
243
  build.setup_frontend_prod,
237
244
  exec.run_frontend_prod,
238
245
  exec.run_backend_prod,
239
246
  )
240
- if not setup_frontend or not frontend_cmd or not backend_cmd:
241
- msg = f"Invalid env: {env}. Must be DEV or PROD."
242
- raise ValueError(msg)
243
247
 
244
248
  # Post a telemetry event.
245
249
  telemetry.send(f"run-{env.value}")
@@ -251,7 +255,7 @@ def _run(
251
255
  commands = []
252
256
 
253
257
  # Run the frontend on a separate thread.
254
- if frontend:
258
+ if frontend and not single_port:
255
259
  setup_frontend(Path.cwd())
256
260
  commands.append((frontend_cmd, Path.cwd(), frontend_port, backend))
257
261
 
@@ -267,21 +271,30 @@ def _run(
267
271
  )
268
272
  )
269
273
 
270
- # Start the frontend and backend.
271
- with processes.run_concurrently_context(*commands):
272
- # In dev mode, run the backend on the main thread.
273
- if backend and backend_port and env == constants.Env.DEV:
274
- backend_cmd(
275
- backend_host,
276
- int(backend_port),
277
- config.loglevel.subprocess_level(),
278
- frontend,
279
- )
280
- # The windows uvicorn bug workaround
281
- # https://github.com/reflex-dev/reflex/issues/2335
282
- if constants.IS_WINDOWS and exec.frontend_process:
283
- # Sends SIGTERM in windows
284
- exec.kill(exec.frontend_process.pid)
274
+ if single_port:
275
+ setup_frontend(Path.cwd())
276
+ backend_function, *args = commands[0]
277
+ exec.notify_app_running()
278
+ exec.notify_frontend(
279
+ f"http://0.0.0.0:{get_config().frontend_port}", backend_present=True
280
+ )
281
+ backend_function(*args, mount_frontend_compiled_app=True)
282
+ else:
283
+ # Start the frontend and backend.
284
+ with processes.run_concurrently_context(*commands):
285
+ # In dev mode, run the backend on the main thread.
286
+ if backend and backend_port and env == constants.Env.DEV:
287
+ backend_cmd(
288
+ backend_host,
289
+ int(backend_port),
290
+ config.loglevel.subprocess_level(),
291
+ frontend,
292
+ )
293
+ # The windows uvicorn bug workaround
294
+ # https://github.com/reflex-dev/reflex/issues/2335
295
+ if constants.IS_WINDOWS and exec.frontend_process:
296
+ # Sends SIGTERM in windows
297
+ exec.kill(exec.frontend_process.pid)
285
298
 
286
299
 
287
300
  @cli.command()
@@ -322,6 +335,12 @@ def _run(
322
335
  "--backend-host",
323
336
  help="Specify the backend host.",
324
337
  )
338
+ @click.option(
339
+ "--single-port",
340
+ is_flag=True,
341
+ help="Run both frontend and backend on the same port.",
342
+ default=False,
343
+ )
325
344
  def run(
326
345
  env: LITERAL_ENV,
327
346
  frontend_only: bool,
@@ -329,11 +348,29 @@ def run(
329
348
  frontend_port: int | None,
330
349
  backend_port: int | None,
331
350
  backend_host: str | None,
351
+ single_port: bool,
332
352
  ):
333
353
  """Run the app in the current directory."""
334
354
  if frontend_only and backend_only:
335
355
  console.error("Cannot use both --frontend-only and --backend-only options.")
336
- raise click.exceptions.Exit(1)
356
+ raise SystemExit(1)
357
+
358
+ if single_port:
359
+ if env != constants.Env.PROD.value:
360
+ console.error("--single-port can only be used with --env=PROD.")
361
+ raise click.exceptions.Exit(1)
362
+ if frontend_only or backend_only:
363
+ console.error(
364
+ "Cannot use --single-port with --frontend-only or --backend-only options."
365
+ )
366
+ raise click.exceptions.Exit(1)
367
+ if backend_port and frontend_port and backend_port != frontend_port:
368
+ console.error(
369
+ "When using --single-port, --backend-port and --frontend-port must be the same."
370
+ )
371
+ raise click.exceptions.Exit(1)
372
+ elif frontend_port and backend_port and frontend_port == backend_port:
373
+ single_port = True
337
374
 
338
375
  config = get_config()
339
376
 
@@ -352,6 +389,7 @@ def run(
352
389
  frontend_port,
353
390
  backend_port,
354
391
  backend_host,
392
+ single_port,
355
393
  )
356
394
 
357
395
 
reflex/state.py CHANGED
@@ -533,7 +533,7 @@ class BaseState(EvenMoreBasicBaseState):
533
533
  cls._check_overridden_computed_vars()
534
534
 
535
535
  new_backend_vars = {
536
- name: value
536
+ name: value if not isinstance(value, Field) else value.default_value()
537
537
  for name, value in list(cls.__dict__.items())
538
538
  if types.is_backend_base_variable(name, cls)
539
539
  }
@@ -1207,7 +1207,8 @@ class BaseState(EvenMoreBasicBaseState):
1207
1207
  The default value of the var or None.
1208
1208
  """
1209
1209
  try:
1210
- return getattr(cls, name)
1210
+ value = getattr(cls, name)
1211
+ return value if not isinstance(value, Field) else value.default_value()
1211
1212
  except AttributeError:
1212
1213
  try:
1213
1214
  return types.get_default_value_for_type(annotation_value)
reflex/utils/exec.py CHANGED
@@ -145,6 +145,18 @@ def kill(proc_pid: int):
145
145
  process.kill()
146
146
 
147
147
 
148
+ def notify_frontend(url: str, backend_present: bool):
149
+ """Output a string notifying where the frontend is running.
150
+
151
+ Args:
152
+ url: The URL where the frontend is running.
153
+ backend_present: Whether the backend is present.
154
+ """
155
+ console.print(
156
+ f"App running at: [bold green]{url.rstrip('/')}/[/bold green]{' (Frontend-only mode)' if not backend_present else ''}"
157
+ )
158
+
159
+
148
160
  def notify_backend():
149
161
  """Output a string notifying where the backend is running."""
150
162
  console.print(
@@ -210,9 +222,7 @@ def run_process_and_launch_url(
210
222
  if get_config().frontend_path != "":
211
223
  url = urljoin(url, get_config().frontend_path)
212
224
 
213
- console.print(
214
- f"App running at: [bold green]{url}[/bold green]{' (Frontend-only mode)' if not backend_present else ''}"
215
- )
225
+ notify_frontend(url, backend_present)
216
226
  if backend_present:
217
227
  notify_backend()
218
228
  first_run = False
@@ -249,6 +259,11 @@ def run_frontend(root: Path, port: str, backend_present: bool = True):
249
259
  )
250
260
 
251
261
 
262
+ def notify_app_running():
263
+ """Notify that the app is running."""
264
+ console.rule("[bold green]App Running")
265
+
266
+
252
267
  def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
253
268
  """Run the frontend.
254
269
 
@@ -264,7 +279,7 @@ def run_frontend_prod(root: Path, port: str, backend_present: bool = True):
264
279
  # validate dependencies before run
265
280
  js_runtimes.validate_frontend_dependencies(init=False)
266
281
  # Run the frontend in production mode.
267
- console.rule("[bold green]App Running")
282
+ notify_app_running()
268
283
  run_process_and_launch_url(
269
284
  [*js_runtimes.get_js_package_executor(raise_on_none=True)[0], "run", "prod"],
270
285
  backend_present,
@@ -552,6 +567,7 @@ def run_backend_prod(
552
567
  port: int,
553
568
  loglevel: constants.LogLevel = constants.LogLevel.ERROR,
554
569
  frontend_present: bool = False,
570
+ mount_frontend_compiled_app: bool = False,
555
571
  ):
556
572
  """Run the backend.
557
573
 
@@ -560,10 +576,13 @@ def run_backend_prod(
560
576
  port: The app port
561
577
  loglevel: The log level.
562
578
  frontend_present: Whether the frontend is present.
579
+ mount_frontend_compiled_app: Whether to mount the compiled frontend app with the backend.
563
580
  """
564
581
  if not frontend_present:
565
582
  notify_backend()
566
583
 
584
+ environment.REFLEX_MOUNT_FRONTEND_COMPILED_APP.set(mount_frontend_compiled_app)
585
+
567
586
  if should_use_granian():
568
587
  run_granian_backend_prod(host, port, loglevel)
569
588
  else:
@@ -5,8 +5,6 @@ import random
5
5
  import re
6
6
  from pathlib import Path
7
7
 
8
- import click
9
-
10
8
  from reflex import constants
11
9
  from reflex.compiler import templates
12
10
  from reflex.config import Config, get_config
@@ -54,7 +52,7 @@ def initialize_requirements_txt() -> bool:
54
52
  True if the user has to update the requirements.txt file.
55
53
 
56
54
  Raises:
57
- Exit: If the requirements.txt file cannot be read or written to.
55
+ SystemExit: If the requirements.txt file cannot be read or written to.
58
56
  """
59
57
  requirements_file_path = Path(constants.RequirementsTxt.FILE)
60
58
  if (
@@ -72,8 +70,8 @@ def initialize_requirements_txt() -> bool:
72
70
  except UnicodeDecodeError:
73
71
  continue
74
72
  except Exception as e:
75
- console.error(f"Failed to read {requirements_file_path}.")
76
- raise click.exceptions.Exit(1) from e
73
+ console.error(f"Failed to read {requirements_file_path} due to {e}.")
74
+ raise SystemExit(1) from None
77
75
  else:
78
76
  return True
79
77