Bläddra i källkod

Issues 1633 Add frontend_path to config to support running multiple reflex apps off the same domain, and 1583 Show the correct info on where the site is being served. (#1724)

* Support setting Next.js basePath in Reflex config. (#1633)

- Tests.
- And sorted config in next.config.js template.

* Display the correct running at url with basePath if it is set. (#1583)

* Formatting, fixed by black.

* Fix indenting in test data.

* Fixed that conflict resolution shouldnt have included console.debug line.

* Rmove use of :=. Add http:// to url. Use urljoin to build url.
Nev Delap 1 år sedan
förälder
incheckning
41e97bbc46

+ 2 - 1
reflex/.templates/web/next.config.js

@@ -1,5 +1,6 @@
 module.exports = {
 module.exports = {
-  reactStrictMode: true,
+  basePath: "",
   compress: true,
   compress: true,
+  reactStrictMode: true,
   trailingSlash: true,
   trailingSlash: true,
 };
 };

+ 3 - 0
reflex/config.py

@@ -138,6 +138,9 @@ class Config(Base):
     # The port to run the frontend on.
     # The port to run the frontend on.
     frontend_port: int = 3000
     frontend_port: int = 3000
 
 
+    # The path to run the frontend on.
+    frontend_path: str = ""
+
     # The port to run the backend on.
     # The port to run the backend on.
     backend_port: int = 8000
     backend_port: int = 8000
 
 

+ 8 - 4
reflex/utils/exec.py

@@ -6,8 +6,10 @@ import hashlib
 import json
 import json
 import os
 import os
 import platform
 import platform
+import re
 import sys
 import sys
 from pathlib import Path
 from pathlib import Path
+from urllib.parse import urljoin
 
 
 import psutil
 import psutil
 import uvicorn
 import uvicorn
@@ -83,13 +85,15 @@ def run_process_and_launch_url(run_command: list[str]):
             )
             )
         if process.stdout:
         if process.stdout:
             for line in processes.stream_logs("Starting frontend", process):
             for line in processes.stream_logs("Starting frontend", process):
-                if "ready started server on" in line:
+                match = re.search("ready started server on ([0-9.:]+)", line)
+                if match:
                     if first_run:
                     if first_run:
-                        url = line.split("url: ")[-1].strip()
+                        url = f"http://{match.group(1)}"
+                        if get_config().frontend_path != "":
+                            url = urljoin(url, get_config().frontend_path)
                         console.print(f"App running at: [bold green]{url}")
                         console.print(f"App running at: [bold green]{url}")
-                        first_run = False
                     else:
                     else:
-                        console.print(f"New packages detected updating app...")
+                        console.print("New packages detected updating app...")
                 else:
                 else:
                     console.debug(line)
                     console.debug(line)
                     new_hash = detect_package_change(json_file_path)
                     new_hash = detect_package_change(json_file_path)

+ 27 - 9
reflex/utils/prerequisites.py

@@ -23,7 +23,7 @@ from packaging import version
 from redis import Redis
 from redis import Redis
 
 
 from reflex import constants, model
 from reflex import constants, model
-from reflex.config import get_config
+from reflex.config import Config, get_config
 from reflex.utils import console, path_ops, processes
 from reflex.utils import console, path_ops, processes
 
 
 
 
@@ -216,16 +216,11 @@ def initialize_web_directory():
     next_config_file = os.path.join(constants.WEB_DIR, constants.NEXT_CONFIG_FILE)
     next_config_file = os.path.join(constants.WEB_DIR, constants.NEXT_CONFIG_FILE)
 
 
     with open(next_config_file, "r") as file:
     with open(next_config_file, "r") as file:
-        lines = file.readlines()
-        for i, line in enumerate(lines):
-            if "compress:" in line:
-                new_line = line.replace(
-                    "true", "true" if get_config().next_compression else "false"
-                )
-                lines[i] = new_line
+        next_config = file.read()
+        next_config = update_next_config(next_config, get_config())
 
 
     with open(next_config_file, "w") as file:
     with open(next_config_file, "w") as file:
-        file.writelines(lines)
+        file.write(next_config)
 
 
     # Initialize the reflex json file.
     # Initialize the reflex json file.
     init_reflex_json()
     init_reflex_json()
@@ -245,6 +240,29 @@ def init_reflex_json():
     path_ops.update_json_file(constants.REFLEX_JSON, reflex_json)
     path_ops.update_json_file(constants.REFLEX_JSON, reflex_json)
 
 
 
 
+def update_next_config(next_config: str, config: Config) -> str:
+    """Update Next.js config from Reflex config. Is its own function for testing.
+
+    Args:
+        next_config: Content of next.config.js.
+        config: A reflex Config object.
+
+    Returns:
+        The next_config updated from config.
+    """
+    next_config = re.sub(
+        "compress: (true|false)",
+        f'compress: {"true" if config.next_compression else "false"}',
+        next_config,
+    )
+    next_config = re.sub(
+        'basePath: ".*?"',
+        f'basePath: "{config.frontend_path or ""}"',
+        next_config,
+    )
+    return next_config
+
+
 def remove_existing_bun_installation():
 def remove_existing_bun_installation():
     """Remove existing bun installation."""
     """Remove existing bun installation."""
     console.debug("Removing existing bun installation.")
     console.debug("Removing existing bun installation.")

+ 1 - 0
tests/test_config.py

@@ -47,6 +47,7 @@ def test_deprecated_params(base_config_values, param):
     [
     [
         ("APP_NAME", "my_test_app"),
         ("APP_NAME", "my_test_app"),
         ("FRONTEND_PORT", 3001),
         ("FRONTEND_PORT", 3001),
+        ("FRONTEND_PATH", "/test"),
         ("BACKEND_PORT", 8001),
         ("BACKEND_PORT", 8001),
         ("API_URL", "https://mybackend.com:8000"),
         ("API_URL", "https://mybackend.com:8000"),
         ("DEPLOY_URL", "https://myfrontend.com"),
         ("DEPLOY_URL", "https://myfrontend.com"),

+ 103 - 0
tests/test_prerequites.py

@@ -0,0 +1,103 @@
+import pytest
+
+from reflex.config import Config
+from reflex.utils.prerequisites import update_next_config
+
+
+@pytest.mark.parametrize(
+    "template_next_config, reflex_config, expected_next_config",
+    [
+        (
+            """
+                module.exports = {
+                    basePath: "",
+                    compress: true,
+                    reactStrictMode: true,
+                    trailingSlash: true,
+                };
+            """,
+            Config(
+                app_name="test",
+            ),
+            """
+                module.exports = {
+                    basePath: "",
+                    compress: true,
+                    reactStrictMode: true,
+                    trailingSlash: true,
+                };
+            """,
+        ),
+        (
+            """
+                module.exports = {
+                    basePath: "",
+                    compress: true,
+                    reactStrictMode: true,
+                    trailingSlash: true,
+                };
+            """,
+            Config(
+                app_name="test",
+                next_compression=False,
+            ),
+            """
+                module.exports = {
+                    basePath: "",
+                    compress: false,
+                    reactStrictMode: true,
+                    trailingSlash: true,
+                };
+            """,
+        ),
+        (
+            """
+                module.exports = {
+                    basePath: "",
+                    compress: true,
+                    reactStrictMode: true,
+                    trailingSlash: true,
+                };
+            """,
+            Config(
+                app_name="test",
+                frontend_path="/test",
+            ),
+            """
+                module.exports = {
+                    basePath: "/test",
+                    compress: true,
+                    reactStrictMode: true,
+                    trailingSlash: true,
+                };
+            """,
+        ),
+        (
+            """
+                module.exports = {
+                    basePath: "",
+                    compress: true,
+                    reactStrictMode: true,
+                    trailingSlash: true,
+                };
+            """,
+            Config(
+                app_name="test",
+                frontend_path="/test",
+                next_compression=False,
+            ),
+            """
+                module.exports = {
+                    basePath: "/test",
+                    compress: false,
+                    reactStrictMode: true,
+                    trailingSlash: true,
+                };
+            """,
+        ),
+    ],
+)
+def test_update_next_config(template_next_config, reflex_config, expected_next_config):
+    assert (
+        update_next_config(template_next_config, reflex_config) == expected_next_config
+    )