Browse Source

replace dependency paths in URL with IDs

Falko Schindler 2 years ago
parent
commit
ca6ae64fdf
4 changed files with 72 additions and 32 deletions
  1. 3 2
      nicegui/client.py
  2. 26 0
      nicegui/ids.py
  3. 7 7
      nicegui/nicegui.py
  4. 36 23
      nicegui/vue.py

+ 3 - 2
nicegui/client.py

@@ -12,19 +12,20 @@ from fastapi.templating import Jinja2Templates
 from . import globals, vue
 from .element import Element
 from .favicon import get_favicon_url
+from .ids import IncrementingIds
 from .task_logger import create_task
 
 if TYPE_CHECKING:
     from .page import page
 
 templates = Jinja2Templates(Path(__file__).parent / 'templates')
+client_ids = IncrementingIds()
 
 
 class Client:
 
     def __init__(self, page: 'page', *, shared: bool = False) -> None:
-        self.id = globals.next_client_id
-        globals.next_client_id += 1
+        self.id = client_ids.get()
         globals.clients[self.id] = self
 
         self.elements: Dict[str, Element] = {}

+ 26 - 0
nicegui/ids.py

@@ -0,0 +1,26 @@
+from typing import Dict
+
+
+class IncrementingIds:
+    '''Generates incrementing IDs'''
+
+    def __init__(self) -> None:
+        self.current_id = -1
+
+    def get(self) -> int:
+        self.current_id += 1
+        return self.current_id
+
+
+class IncrementingStringIds:
+    '''Maps incrementing IDs to given strings'''
+
+    def __init__(self) -> None:
+        self.current_id = -1
+        self.dict: Dict[str, int] = {}
+
+    def get(self, name: str) -> int:
+        if name not in self.dict:
+            self.current_id += 1
+            self.dict[name] = self.current_id
+        return self.dict[name]

+ 7 - 7
nicegui/nicegui.py

@@ -32,16 +32,16 @@ def index(request: Request) -> str:
     return globals.index_client.build_response(request)
 
 
-@app.get('/_vue/dependencies/{path:path}')
-def vue_dependencies(path: str):
-    if Path(path).exists() and vue.is_js_dependency(Path(path)):
-        return FileResponse(path, media_type='text/javascript')
-    raise HTTPException(status_code=404, detail=f'{path} not found')
+@app.get('/_nicegui/dependencies/{id}/{name}')
+def vue_dependencies(id: int, name: str):
+    if id in vue.js_dependencies and vue.js_dependencies[id].path.exists():
+        return FileResponse(vue.js_dependencies[id].path, media_type='text/javascript')
+    raise HTTPException(status_code=404, detail=f'dependency "{name}" with ID {id} not found')
 
 
-@app.get('/_vue/components/{name}')
+@app.get('/_nicegui/components/{name}')
 def vue_dependencies(name: str):
-    return FileResponse(vue.js_components[name], media_type='text/javascript')
+    return FileResponse(vue.js_components[name].path, media_type='text/javascript')
 
 
 @app.on_event('startup')

+ 36 - 23
nicegui/vue.py

@@ -1,13 +1,31 @@
+from dataclasses import dataclass
 from pathlib import Path
-from typing import Dict, List, Tuple
+from typing import Dict, List, Set, Tuple
 
 import vbuild
 
 from . import globals
+from .ids import IncrementingStringIds
 
-vue_components: Dict[str, Path] = {}
-js_components: Dict[str, Path] = {}
-js_dependencies: Dict[str, List[Path]] = {}
+
+@dataclass
+class Component:
+    name: str
+    path: Path
+
+
+@dataclass
+class Dependency:
+    id: int
+    path: Path
+    dependents: Set[str]
+
+
+dependency_ids = IncrementingStringIds()
+
+vue_components: Dict[str, Component] = {}
+js_components: Dict[str, Component] = {}
+js_dependencies: Dict[int, Dependency] = {}
 
 
 def register_component(name: str, py_filepath: str, component_filepath: str, dependencies: List[str] = []) -> None:
@@ -15,20 +33,23 @@ def register_component(name: str, py_filepath: str, component_filepath: str, dep
     assert suffix in ['.vue', '.js'], 'Only VUE and JS components are supported.'
     if suffix == '.vue':
         assert name not in vue_components, f'Duplicate VUE component name {name}'
-        vue_components[name] = Path(py_filepath).parent / component_filepath
+        vue_components[name] = Component(name=name, path=Path(py_filepath).parent / component_filepath)
     elif suffix == '.js':
         assert name not in js_components, f'Duplicate JS component name {name}'
-        js_components[name] = Path(py_filepath).parent / component_filepath
-    js_dependencies[name] = []
+        js_components[name] = Component(name=name, path=Path(py_filepath).parent / component_filepath)
     for dependency in dependencies:
-        assert Path(dependency).suffix == '.js', 'Only JS dependencies are supported.'
-        js_dependencies[name].append(Path(py_filepath).parent / dependency)
+        path = Path(py_filepath).parent / dependency
+        assert path.suffix == '.js', 'Only JS dependencies are supported.'
+        id = dependency_ids.get(str(path.resolve()))
+        if id not in js_dependencies:
+            js_dependencies[id] = Dependency(id=id, path=path, dependents=set())
+        js_dependencies[id].dependents.add(name)
 
 
 def generate_vue_content() -> Tuple[str]:
     builds = [
-        vbuild.VBuild(name, path.read_text())
-        for name, path in vue_components.items()
+        vbuild.VBuild(name, component.path.read_text())
+        for name, component in vue_components.items()
         if name not in globals.excludes
     ]
     return (
@@ -40,21 +61,13 @@ def generate_vue_content() -> Tuple[str]:
 
 def generate_js_imports(prefix: str) -> str:
     result = ''
-    for name in vue_components:
-        if name in globals.excludes:
+    for id, dependency in js_dependencies.items():
+        if not dependency.dependents.difference(globals.excludes):
             continue
-        for path in js_dependencies[name]:
-            result += f'import "{prefix}/_vue/dependencies/{path}";\n'
+        result += f'import "{prefix}/_nicegui/dependencies/{id}/{dependency.path.name}";\n'
     for name in js_components:
         if name in globals.excludes:
             continue
-        for path in js_dependencies[name]:
-            result += f'import "{prefix}/_vue/dependencies/{path}";\n'
-        result += f'import {{ default as {name} }} from "{prefix}/_vue/components/{name}";\n'
+        result += f'import {{ default as {name} }} from "{prefix}/_nicegui/components/{name}";\n'
         result += f'app.component("{name}", {name});\n'
     return result
-
-
-def is_js_dependency(path: Path) -> bool:
-    return any(path in js_dependencies[name] for name in vue_components) or \
-        any(path in js_dependencies[name] for name in js_components)