Browse Source

allow for non-installable imports (#1843)

Thomas Brandého 1 year ago
parent
commit
15ced6b795
5 changed files with 33 additions and 16 deletions
  1. 4 2
      reflex/app.py
  2. 6 5
      reflex/compiler/utils.py
  3. 12 8
      reflex/components/component.py
  4. 9 1
      reflex/vars.py
  5. 2 0
      reflex/vars.pyi

+ 4 - 2
reflex/app.py

@@ -51,6 +51,7 @@ from reflex.route import (
 )
 )
 from reflex.state import DefaultState, State, StateManager, StateUpdate
 from reflex.state import DefaultState, State, StateManager, StateUpdate
 from reflex.utils import console, format, prerequisites, types
 from reflex.utils import console, format, prerequisites, types
+from reflex.vars import ImportVar
 
 
 # Define custom types.
 # Define custom types.
 ComponentCallable = Callable[[], Component]
 ComponentCallable = Callable[[], Component]
@@ -508,7 +509,7 @@ class App(Base):
 
 
             admin.mount_to(self.api)
             admin.mount_to(self.api)
 
 
-    def get_frontend_packages(self, imports: Dict[str, str]):
+    def get_frontend_packages(self, imports: Dict[str, set[ImportVar]]):
         """Gets the frontend packages to be installed and filters out the unnecessary ones.
         """Gets the frontend packages to be installed and filters out the unnecessary ones.
 
 
         Args:
         Args:
@@ -519,13 +520,14 @@ class App(Base):
         """
         """
         page_imports = {
         page_imports = {
             i
             i
-            for i in imports
+            for i, tags in imports.items()
             if i not in compiler.DEFAULT_IMPORTS.keys()
             if i not in compiler.DEFAULT_IMPORTS.keys()
             and i != "focus-visible/dist/focus-visible"
             and i != "focus-visible/dist/focus-visible"
             and "next" not in i
             and "next" not in i
             and not i.startswith("/")
             and not i.startswith("/")
             and not i.startswith(".")
             and not i.startswith(".")
             and i != ""
             and i != ""
+            and any(tag.install for tag in tags)
         }
         }
         frontend_packages = get_config().frontend_packages
         frontend_packages = get_config().frontend_packages
         _frontend_packages = []
         _frontend_packages = []

+ 6 - 5
reflex/compiler/utils.py

@@ -25,7 +25,7 @@ from reflex.components.component import Component, ComponentStyle, CustomCompone
 from reflex.state import Cookie, LocalStorage, State
 from reflex.state import Cookie, LocalStorage, State
 from reflex.style import Style
 from reflex.style import Style
 from reflex.utils import format, imports, path_ops
 from reflex.utils import format, imports, path_ops
-from reflex.vars import ImportVar, NoRenderImportVar
+from reflex.vars import ImportVar
 
 
 # To re-export this function.
 # To re-export this function.
 merge_imports = imports.merge_imports
 merge_imports = imports.merge_imports
@@ -42,8 +42,8 @@ def compile_import_statement(fields: Set[ImportVar]) -> Tuple[str, Set[str]]:
         default: default library. When install "import def from library".
         default: default library. When install "import def from library".
         rest: rest of libraries. When install "import {rest1, rest2} from library"
         rest: rest of libraries. When install "import {rest1, rest2} from library"
     """
     """
-    # ignore the NoRenderImportVar fields during compilation
-    fields = {field for field in fields if not isinstance(field, NoRenderImportVar)}
+    # ignore the ImportVar fields with render=False during compilation
+    fields = {field for field in fields if field.render}
 
 
     # Check for default imports.
     # Check for default imports.
     defaults = {field for field in fields if field.is_default}
     defaults = {field for field in fields if field.is_default}
@@ -91,8 +91,9 @@ def compile_imports(imports: imports.ImportDict) -> List[dict]:
     import_dicts = []
     import_dicts = []
     for lib, fields in imports.items():
     for lib, fields in imports.items():
         default, rest = compile_import_statement(fields)
         default, rest = compile_import_statement(fields)
-        # prevent lib from being rendered on the page if all imports are NoRenderImportVar
-        if all({isinstance(f, NoRenderImportVar) for f in fields}):  # type: ignore
+
+        # prevent lib from being rendered on the page if all imports are non rendered kind
+        if all({not f.render for f in fields}):  # type: ignore
             continue
             continue
 
 
         if not lib:
         if not lib:

+ 12 - 8
reflex/components/component.py

@@ -22,7 +22,7 @@ from reflex.event import (
 )
 )
 from reflex.style import Style
 from reflex.style import Style
 from reflex.utils import format, imports, types
 from reflex.utils import format, imports, types
-from reflex.vars import BaseVar, ImportVar, NoRenderImportVar, Var
+from reflex.vars import BaseVar, ImportVar, Var
 
 
 
 
 class Component(Base, ABC):
 class Component(Base, ABC):
@@ -546,13 +546,16 @@ class Component(Base, ABC):
         # Return the dynamic imports
         # Return the dynamic imports
         return dynamic_imports
         return dynamic_imports
 
 
+    def _get_dependencies_imports(self):
+        return {
+            dep: {ImportVar(tag=None, render=False)} for dep in self.lib_dependencies
+        }
+
     def _get_imports(self) -> imports.ImportDict:
     def _get_imports(self) -> imports.ImportDict:
         imports = {}
         imports = {}
         if self.library is not None and self.tag is not None:
         if self.library is not None and self.tag is not None:
             imports[self.library] = {self.import_var}
             imports[self.library] = {self.import_var}
-        for dep in self.lib_dependencies:
-            imports[dep] = {NoRenderImportVar()}  # type: ignore
-        return imports
+        return {**imports, **self._get_dependencies_imports()}
 
 
     def get_imports(self) -> imports.ImportDict:
     def get_imports(self) -> imports.ImportDict:
         """Get all the libraries and fields that are used by the component.
         """Get all the libraries and fields that are used by the component.
@@ -870,10 +873,11 @@ class NoSSRComponent(Component):
     def _get_imports(self):
     def _get_imports(self):
         imports = {"next/dynamic": {ImportVar(tag="dynamic", is_default=True)}}
         imports = {"next/dynamic": {ImportVar(tag="dynamic", is_default=True)}}
 
 
-        for dep in [self.library, *self.lib_dependencies]:
-            imports[dep] = {NoRenderImportVar()}  # type: ignore
-
-        return imports
+        return {
+            **imports,
+            self.library: {ImportVar(tag=None, render=False)},
+            **self._get_dependencies_imports(),
+        }
 
 
     def _get_dynamic_imports(self) -> str:
     def _get_dynamic_imports(self) -> str:
         opts_fragment = ", { ssr: false });"
         opts_fragment = ", { ssr: false });"

+ 9 - 1
reflex/vars.py

@@ -1332,6 +1332,12 @@ class ImportVar(Base):
     # The tag alias.
     # The tag alias.
     alias: Optional[str] = None
     alias: Optional[str] = None
 
 
+    # Whether this import need to install the associated lib
+    install: Optional[bool] = True
+
+    # whether this import should be rendered or not
+    render: Optional[bool] = True
+
     @property
     @property
     def name(self) -> str:
     def name(self) -> str:
         """The name of the import.
         """The name of the import.
@@ -1347,12 +1353,14 @@ class ImportVar(Base):
         Returns:
         Returns:
             The hash of the var.
             The hash of the var.
         """
         """
-        return hash((self.tag, self.is_default, self.alias))
+        return hash((self.tag, self.is_default, self.alias, self.install, self.render))
 
 
 
 
 class NoRenderImportVar(ImportVar):
 class NoRenderImportVar(ImportVar):
     """A import that doesn't need to be rendered."""
     """A import that doesn't need to be rendered."""
 
 
+    render: Optional[bool] = False
+
 
 
 def get_local_storage(key: Var | str | None = None) -> BaseVar:
 def get_local_storage(key: Var | str | None = None) -> BaseVar:
     """Provide a base var as payload to get local storage item(s).
     """Provide a base var as payload to get local storage item(s).

+ 2 - 0
reflex/vars.pyi

@@ -120,6 +120,8 @@ class ImportVar(Base):
     tag: Optional[str]
     tag: Optional[str]
     is_default: Optional[bool] = False
     is_default: Optional[bool] = False
     alias: Optional[str] = None
     alias: Optional[str] = None
+    install: Optional[bool] = True
+    render: Optional[bool] = True
     @property
     @property
     def name(self) -> str: ...
     def name(self) -> str: ...
     def __hash__(self) -> int: ...
     def __hash__(self) -> int: ...