|
@@ -16,6 +16,7 @@ import zipfile
|
|
|
from fileinput import FileInput
|
|
|
from pathlib import Path
|
|
|
from types import ModuleType
|
|
|
+from typing import Callable
|
|
|
|
|
|
import httpx
|
|
|
import pkg_resources
|
|
@@ -26,7 +27,7 @@ from redis.asyncio import Redis
|
|
|
|
|
|
from reflex import constants, model
|
|
|
from reflex.compiler import templates
|
|
|
-from reflex.config import get_config
|
|
|
+from reflex.config import Config, get_config
|
|
|
from reflex.utils import console, path_ops, processes
|
|
|
|
|
|
|
|
@@ -619,14 +620,64 @@ def install_bun():
|
|
|
)
|
|
|
|
|
|
|
|
|
-def install_frontend_packages(packages: set[str]):
|
|
|
+def _write_cached_procedure_file(payload: str, cache_file: str):
|
|
|
+ with open(cache_file, "w") as f:
|
|
|
+ f.write(payload)
|
|
|
+
|
|
|
+
|
|
|
+def _read_cached_procedure_file(cache_file: str) -> str | None:
|
|
|
+ if os.path.exists(cache_file):
|
|
|
+ with open(cache_file, "r") as f:
|
|
|
+ return f.read()
|
|
|
+ return None
|
|
|
+
|
|
|
+
|
|
|
+def _clear_cached_procedure_file(cache_file: str):
|
|
|
+ if os.path.exists(cache_file):
|
|
|
+ os.remove(cache_file)
|
|
|
+
|
|
|
+
|
|
|
+def cached_procedure(cache_file: str, payload_fn: Callable[..., str]):
|
|
|
+ """Decorator to cache the runs of a procedure on disk. Procedures should not have
|
|
|
+ a return value.
|
|
|
+
|
|
|
+ Args:
|
|
|
+ cache_file: The file to store the cache payload in.
|
|
|
+ payload_fn: Function that computes cache payload from function args
|
|
|
+
|
|
|
+ Returns:
|
|
|
+ The decorated function.
|
|
|
+ """
|
|
|
+
|
|
|
+ def _inner_decorator(func):
|
|
|
+ def _inner(*args, **kwargs):
|
|
|
+ payload = _read_cached_procedure_file(cache_file)
|
|
|
+ new_payload = payload_fn(*args, **kwargs)
|
|
|
+ if payload != new_payload:
|
|
|
+ _clear_cached_procedure_file(cache_file)
|
|
|
+ func(*args, **kwargs)
|
|
|
+ _write_cached_procedure_file(new_payload, cache_file)
|
|
|
+
|
|
|
+ return _inner
|
|
|
+
|
|
|
+ return _inner_decorator
|
|
|
+
|
|
|
+
|
|
|
+@cached_procedure(
|
|
|
+ cache_file=os.path.join(
|
|
|
+ constants.Dirs.WEB, "reflex.install_frontend_packages.cached"
|
|
|
+ ),
|
|
|
+ payload_fn=lambda p, c: f"{repr(sorted(list(p)))},{c.json()}",
|
|
|
+)
|
|
|
+def install_frontend_packages(packages: set[str], config: Config):
|
|
|
"""Installs the base and custom frontend packages.
|
|
|
|
|
|
Args:
|
|
|
packages: A list of package names to be installed.
|
|
|
+ config: The config object.
|
|
|
|
|
|
Example:
|
|
|
- >>> install_frontend_packages(["react", "react-dom"])
|
|
|
+ >>> install_frontend_packages(["react", "react-dom"], get_config())
|
|
|
"""
|
|
|
# Install the base packages.
|
|
|
process = processes.new_process(
|
|
@@ -637,7 +688,6 @@ def install_frontend_packages(packages: set[str]):
|
|
|
|
|
|
processes.show_status("Installing base frontend packages", process)
|
|
|
|
|
|
- config = get_config()
|
|
|
if config.tailwind is not None:
|
|
|
# install tailwind and tailwind plugins as dev dependencies.
|
|
|
process = processes.new_process(
|