Skip frontend packages install if previously done (#2400)
This commit is contained in:
parent
1aca1b677f
commit
2c270585ab
@ -595,7 +595,7 @@ class App(Base):
|
||||
continue
|
||||
_frontend_packages.append(package)
|
||||
page_imports.update(_frontend_packages)
|
||||
prerequisites.install_frontend_packages(page_imports)
|
||||
prerequisites.install_frontend_packages(page_imports, get_config())
|
||||
|
||||
def _app_root(self, app_wrappers: dict[tuple[int, str], Component]) -> Component:
|
||||
for component in tuple(app_wrappers.values()):
|
||||
|
@ -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(
|
||||
|
@ -1,10 +1,15 @@
|
||||
import tempfile
|
||||
from unittest.mock import Mock, mock_open
|
||||
|
||||
import pytest
|
||||
|
||||
from reflex import constants
|
||||
from reflex.config import Config
|
||||
from reflex.utils.prerequisites import _update_next_config, initialize_requirements_txt
|
||||
from reflex.utils.prerequisites import (
|
||||
_update_next_config,
|
||||
cached_procedure,
|
||||
initialize_requirements_txt,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@ -139,3 +144,36 @@ def test_requirements_txt_other_encoding(mocker):
|
||||
open_mock().write.call_args[0][0]
|
||||
== f"\n{constants.RequirementsTxt.DEFAULTS_STUB}{constants.Reflex.VERSION}\n"
|
||||
)
|
||||
|
||||
|
||||
def test_cached_procedure():
|
||||
call_count = 0
|
||||
|
||||
@cached_procedure(tempfile.mktemp(), payload_fn=lambda: "constant")
|
||||
def _function_with_no_args():
|
||||
nonlocal call_count
|
||||
call_count += 1
|
||||
|
||||
_function_with_no_args()
|
||||
assert call_count == 1
|
||||
_function_with_no_args()
|
||||
assert call_count == 1
|
||||
|
||||
call_count = 0
|
||||
|
||||
@cached_procedure(
|
||||
tempfile.mktemp(),
|
||||
payload_fn=lambda *args, **kwargs: f"{repr(args), repr(kwargs)}",
|
||||
)
|
||||
def _function_with_some_args(*args, **kwargs):
|
||||
nonlocal call_count
|
||||
call_count += 1
|
||||
|
||||
_function_with_some_args(1, y=2)
|
||||
assert call_count == 1
|
||||
_function_with_some_args(1, y=2)
|
||||
assert call_count == 1
|
||||
_function_with_some_args(100, y=300)
|
||||
assert call_count == 2
|
||||
_function_with_some_args(100, y=300)
|
||||
assert call_count == 2
|
||||
|
Loading…
Reference in New Issue
Block a user