Perf Optimization: use the imports we already calculate during compile
Instead of augmenting _get_imports with a weird, slow, recursive crawl and dictionary reconstruction, just use the imports that we compile into the components.js file to install frontend packages needed by the custom components. Same effect, but adds essentially zero overhead to the compilation.
This commit is contained in:
parent
67624b48df
commit
e13ff71c2c
@ -818,6 +818,7 @@ class App(Base):
|
||||
compile_results.append((stateful_components_path, stateful_components_code))
|
||||
|
||||
result_futures = []
|
||||
custom_components_future = None
|
||||
|
||||
def submit_work(fn, *args, **kwargs):
|
||||
"""Submit work to the thread pool and add a callback to mark the task as complete.
|
||||
@ -847,7 +848,10 @@ class App(Base):
|
||||
submit_work(compiler.compile_app, app_root)
|
||||
|
||||
# Compile the custom components.
|
||||
submit_work(compiler.compile_components, custom_components)
|
||||
custom_components_future = thread_pool.submit(
|
||||
compiler.compile_components, custom_components
|
||||
)
|
||||
custom_components_future.add_done_callback(mark_complete)
|
||||
|
||||
# Compile the root stylesheet with base styles.
|
||||
submit_work(compiler.compile_root_stylesheet, self.stylesheets)
|
||||
@ -878,14 +882,15 @@ class App(Base):
|
||||
# Get imports from AppWrap components.
|
||||
all_imports.update(app_root.get_imports())
|
||||
|
||||
# Iterate through all the custom components and add their imports to the all_imports.
|
||||
for component in custom_components:
|
||||
all_imports.update(component.get_imports())
|
||||
|
||||
# Wait for all compilation tasks to complete.
|
||||
for future in concurrent.futures.as_completed(result_futures):
|
||||
compile_results.append(future.result())
|
||||
|
||||
# Iterate through all the custom components and add their imports to the all_imports.
|
||||
custom_components_result = custom_components_future.result()
|
||||
compile_results.append(custom_components_result[:2])
|
||||
all_imports.update(custom_components_result[2])
|
||||
|
||||
# Empty the .web pages directory.
|
||||
compiler.purge_web_pages_dir()
|
||||
|
||||
|
@ -186,7 +186,9 @@ def _compile_component(component: Component) -> str:
|
||||
return templates.COMPONENT.render(component=component)
|
||||
|
||||
|
||||
def _compile_components(components: set[CustomComponent]) -> str:
|
||||
def _compile_components(
|
||||
components: set[CustomComponent],
|
||||
) -> tuple[str, Dict[str, list[ImportVar]]]:
|
||||
"""Compile the components.
|
||||
|
||||
Args:
|
||||
@ -208,9 +210,12 @@ def _compile_components(components: set[CustomComponent]) -> str:
|
||||
imports = utils.merge_imports(imports, component_imports)
|
||||
|
||||
# Compile the components page.
|
||||
return templates.COMPONENTS.render(
|
||||
imports=utils.compile_imports(imports),
|
||||
components=component_renders,
|
||||
return (
|
||||
templates.COMPONENTS.render(
|
||||
imports=utils.compile_imports(imports),
|
||||
components=component_renders,
|
||||
),
|
||||
imports,
|
||||
)
|
||||
|
||||
|
||||
@ -401,7 +406,9 @@ def compile_page(
|
||||
return output_path, code
|
||||
|
||||
|
||||
def compile_components(components: set[CustomComponent]):
|
||||
def compile_components(
|
||||
components: set[CustomComponent],
|
||||
) -> tuple[str, str, Dict[str, list[ImportVar]]]:
|
||||
"""Compile the custom components.
|
||||
|
||||
Args:
|
||||
@ -414,8 +421,8 @@ def compile_components(components: set[CustomComponent]):
|
||||
output_path = utils.get_components_path()
|
||||
|
||||
# Compile the components.
|
||||
code = _compile_components(components)
|
||||
return output_path, code
|
||||
code, imports = _compile_components(components)
|
||||
return output_path, code, imports
|
||||
|
||||
|
||||
def compile_stateful_components(
|
||||
|
@ -1339,31 +1339,6 @@ class CustomComponent(Component):
|
||||
"""
|
||||
return hash(self.tag)
|
||||
|
||||
def _get_imports(self) -> Dict[str, List[ImportVar]]:
|
||||
"""Get the imports for the component.
|
||||
|
||||
This is needed because otherwise the imports for the component are not
|
||||
installed during compile time, but they are rendered into the page.
|
||||
|
||||
Returns:
|
||||
The imports for the component and any custom component props.
|
||||
"""
|
||||
return imports.merge_imports(
|
||||
super()._get_imports(),
|
||||
# Sweep up any imports from CustomComponent props for frontend installation.
|
||||
{
|
||||
library: [
|
||||
ImportVar(
|
||||
tag=None,
|
||||
render=False,
|
||||
install=any(imp.install for imp in imps),
|
||||
),
|
||||
]
|
||||
for comp in self.get_custom_components()
|
||||
for library, imps in comp.get_component(comp).get_imports().items()
|
||||
},
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_props(cls) -> Set[str]:
|
||||
"""Get the props for the component.
|
||||
|
@ -4,6 +4,7 @@ import pytest
|
||||
|
||||
import reflex as rx
|
||||
from reflex.base import Base
|
||||
from reflex.compiler.compiler import compile_components
|
||||
from reflex.components.base.bare import Bare
|
||||
from reflex.components.chakra.layout.box import Box
|
||||
from reflex.components.component import (
|
||||
@ -1289,8 +1290,21 @@ def test_custom_component_get_imports():
|
||||
return Other.create(c)
|
||||
|
||||
custom_comp = wrapper()
|
||||
assert "inner" in custom_comp.get_imports()
|
||||
|
||||
# Inner is not imported directly, but it is imported by the custom component.
|
||||
assert "inner" not in custom_comp.get_imports()
|
||||
|
||||
# The imports are only resolved during compilation.
|
||||
_, _, imports_inner = compile_components(custom_comp.get_custom_components())
|
||||
assert "inner" in imports_inner
|
||||
|
||||
outer_comp = outer(c=wrapper())
|
||||
assert "inner" in outer_comp.get_imports()
|
||||
assert "other" in outer_comp.get_imports()
|
||||
|
||||
# Libraries are not imported directly, but are imported by the custom component.
|
||||
assert "inner" not in outer_comp.get_imports()
|
||||
assert "other" not in outer_comp.get_imports()
|
||||
|
||||
# The imports are only resolved during compilation.
|
||||
_, _, imports_outer = compile_components(outer_comp.get_custom_components())
|
||||
assert "inner" in imports_outer
|
||||
assert "other" in imports_outer
|
||||
|
Loading…
Reference in New Issue
Block a user