Forráskód Böngészése

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.
Masen Furer 1 éve
szülő
commit
e13ff71c2c

+ 10 - 5
reflex/app.py

@@ -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()
 

+ 14 - 7
reflex/compiler/compiler.py

@@ -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(

+ 0 - 25
reflex/components/component.py

@@ -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.

+ 17 - 3
tests/components/test_component.py

@@ -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