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
|
continue
|
||||||
_frontend_packages.append(package)
|
_frontend_packages.append(package)
|
||||||
page_imports.update(_frontend_packages)
|
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:
|
def _app_root(self, app_wrappers: dict[tuple[int, str], Component]) -> Component:
|
||||||
for component in tuple(app_wrappers.values()):
|
for component in tuple(app_wrappers.values()):
|
||||||
|
@ -16,6 +16,7 @@ import zipfile
|
|||||||
from fileinput import FileInput
|
from fileinput import FileInput
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from types import ModuleType
|
from types import ModuleType
|
||||||
|
from typing import Callable
|
||||||
|
|
||||||
import httpx
|
import httpx
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
@ -26,7 +27,7 @@ from redis.asyncio import Redis
|
|||||||
|
|
||||||
from reflex import constants, model
|
from reflex import constants, model
|
||||||
from reflex.compiler import templates
|
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
|
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.
|
"""Installs the base and custom frontend packages.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
packages: A list of package names to be installed.
|
packages: A list of package names to be installed.
|
||||||
|
config: The config object.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
>>> install_frontend_packages(["react", "react-dom"])
|
>>> install_frontend_packages(["react", "react-dom"], get_config())
|
||||||
"""
|
"""
|
||||||
# Install the base packages.
|
# Install the base packages.
|
||||||
process = processes.new_process(
|
process = processes.new_process(
|
||||||
@ -637,7 +688,6 @@ def install_frontend_packages(packages: set[str]):
|
|||||||
|
|
||||||
processes.show_status("Installing base frontend packages", process)
|
processes.show_status("Installing base frontend packages", process)
|
||||||
|
|
||||||
config = get_config()
|
|
||||||
if config.tailwind is not None:
|
if config.tailwind is not None:
|
||||||
# install tailwind and tailwind plugins as dev dependencies.
|
# install tailwind and tailwind plugins as dev dependencies.
|
||||||
process = processes.new_process(
|
process = processes.new_process(
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
|
import tempfile
|
||||||
from unittest.mock import Mock, mock_open
|
from unittest.mock import Mock, mock_open
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from reflex import constants
|
from reflex import constants
|
||||||
from reflex.config import Config
|
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(
|
@pytest.mark.parametrize(
|
||||||
@ -139,3 +144,36 @@ def test_requirements_txt_other_encoding(mocker):
|
|||||||
open_mock().write.call_args[0][0]
|
open_mock().write.call_args[0][0]
|
||||||
== f"\n{constants.RequirementsTxt.DEFAULTS_STUB}{constants.Reflex.VERSION}\n"
|
== 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