From 40ed16a7657b31013f2e35fbf940394110a6ca6e Mon Sep 17 00:00:00 2001
From: Masen Furer <m_github@0x26.net>
Date: Tue, 14 May 2024 11:09:13 -0700
Subject: [PATCH] WiP: in prod mode, export frontend as static files

---
 reflex/app.py    |  7 +++++++
 reflex/reflex.py | 23 ++++++++++++++++++++---
 2 files changed, 27 insertions(+), 3 deletions(-)

diff --git a/reflex/app.py b/reflex/app.py
index 4d99d6949..aabcb1a08 100644
--- a/reflex/app.py
+++ b/reflex/app.py
@@ -212,6 +212,13 @@ class App(Base):
         # Set up the admin dash.
         self._setup_admin_dash()
 
+        if os.environ.get(constants.ENV_MODE_ENV_VAR) == constants.Env.PROD.value:
+            static_dir = constants.Dirs.WEB_STATIC
+            if os.path.exists(static_dir):
+                self.api.mount(
+                    "/", StaticFiles(directory=static_dir, html=True), name="frontend"
+                )
+
     def _enable_state(self) -> None:
         """Enable state for the app."""
         if not self.state:
diff --git a/reflex/reflex.py b/reflex/reflex.py
index 010cceaeb..34f1799e9 100644
--- a/reflex/reflex.py
+++ b/reflex/reflex.py
@@ -132,6 +132,7 @@ def _run(
     backend_port: str = str(config.backend_port),
     backend_host: str = config.backend_host,
     loglevel: constants.LogLevel = config.loglevel,
+    export: bool = False,
 ):
     """Run the app in the given directory."""
     from reflex.utils import build, exec, prerequisites, processes
@@ -179,7 +180,7 @@ def _run(
 
     if frontend:
         # Get the app module.
-        prerequisites.get_compiled_app()
+        prerequisites.get_compiled_app(export=export and env == constants.Env.PROD)
 
     # Warn if schema is not up to date.
     prerequisites.check_schema_up_to_date()
@@ -212,7 +213,11 @@ def _run(
     # Run the frontend on a separate thread.
     if frontend:
         setup_frontend(Path.cwd())
-        commands.append((frontend_cmd, Path.cwd(), frontend_port, backend))
+        if export and env == constants.Env.PROD:
+            # In prod mode, export the frontend and serve it via static files.
+            build.export(backend=False, frontend=True, zip=False)
+        else:
+            commands.append((frontend_cmd, Path.cwd(), frontend_port, backend))
 
     # In prod mode, run the backend on a separate thread.
     if backend and env == constants.Env.PROD:
@@ -251,9 +256,21 @@ def run(
     loglevel: constants.LogLevel = typer.Option(
         config.loglevel, help="The log level to use."
     ),
+    export: bool = typer.Option(
+        False, help="Export the frontend first in production mode."
+    ),
 ):
     """Run the app in the current directory."""
-    _run(env, frontend, backend, frontend_port, backend_port, backend_host, loglevel)
+    _run(
+        env,
+        frontend,
+        backend,
+        frontend_port,
+        backend_port,
+        backend_host,
+        loglevel,
+        export,
+    )
 
 
 @cli.command()