Pārlūkot izejas kodu

using hierachical path names to identify js dependencies

Rodja Trappe 1 gadu atpakaļ
vecāks
revīzija
454b5798cb

+ 13 - 8
nicegui/dependencies.py

@@ -31,15 +31,21 @@ def register_vue_component(name: str, path: Path) -> None:
         js_components[name] = {'name': name, 'path': path}
 
 
-def register_library(name: str, path: Path, *, expose: bool = False) -> None:
+def register_library(
+        location: Path,  base_path: Path = Path(__file__).parent / 'elements' / 'lib', *, expose: bool = False) -> str:
     """Register a new external library.
 
-    :param name: unique machine-name (used in element's `use_library`): no space, no special characters
-    :param path: local path
+    :param location: the location to the library you want to register relative to the base_path. This is also used as the resource identifier (used in element's `use_library`) and must therefore be url-safe.
+    :param base_path: the base path where your libraries are located
     :param expose: if True, this will be exposed as an ESM module but NOT imported
+    :return: the resource identifier library name to be used in element's `use_library`
     """
-    assert path.suffix == '.js' or path.suffix == '.mjs', 'Only JS dependencies are supported.'
-    libraries[name] = {'name': name, 'path': path, 'expose': expose}
+    if isinstance(location, str):
+        return
+    assert location.suffix == '.js' or location.suffix == '.mjs', 'Only JS dependencies are supported.'
+    name = str(location)
+    libraries[name] = {'name': name, 'path': base_path / location,  'expose': expose}
+    return name
 
 
 def generate_resources(prefix: str, elements: List[Element]) -> Tuple[str, str, str, str, str]:
@@ -55,7 +61,7 @@ def generate_resources(prefix: str, elements: List[Element]) -> Tuple[str, str,
     for key in libraries:
         if key not in done_libraries and libraries[key]['expose']:
             name = libraries[key]['name']
-            import_maps['imports'][name] = f'{prefix}/_nicegui/{__version__}/library/{key}/include'
+            import_maps['imports'][name] = f'{prefix}/_nicegui/{__version__}/library/{key}'
             done_libraries.add(key)
     # Build the none optimized component (ie, the vue component).
     for key in vue_components:
@@ -70,7 +76,7 @@ def generate_resources(prefix: str, elements: List[Element]) -> Tuple[str, str,
         for key in element.libraries:
             if key in libraries and key not in done_libraries:
                 if not libraries[key]['expose']:
-                    js_imports += f'import "{prefix}/_nicegui/{__version__}/library/{key}/include";\n'
+                    js_imports += f'import "{prefix}/_nicegui/{__version__}/library/{key}";\n'
                 done_libraries.add(key)
         for key in element.components:
             if key in js_components and key not in done_components:
@@ -79,7 +85,6 @@ def generate_resources(prefix: str, elements: List[Element]) -> Tuple[str, str,
                 js_imports += f'import {{ default as {var} }} from "{prefix}/_nicegui/{__version__}/components/{key}";\n'
                 js_imports += f'app.component("{name}", {var});\n'
                 done_components.add(key)
-
     vue_styles = f'<style>{vue_styles}</style>'
     import_maps = f'<script type="importmap">{json.dumps(import_maps)}</script>'
     return vue_html, vue_styles, vue_scripts, import_maps, js_imports

+ 2 - 2
nicegui/elements/aggrid.py

@@ -8,7 +8,7 @@ from ..element import Element
 from ..functions.javascript import run_javascript
 
 register_vue_component('aggrid', Path(__file__).parent / 'aggrid.js')
-register_library('aggrid', Path(__file__).parent / 'lib' / 'aggrid' / 'ag-grid-community.min.js')
+library_name = register_library(Path('aggrid') / 'ag-grid-community.min.js')
 
 
 class AgGrid(Element):
@@ -29,7 +29,7 @@ class AgGrid(Element):
         self._props['html_columns'] = html_columns
         self._classes = ['nicegui-aggrid', f'ag-theme-{theme}']
         self.use_component('aggrid')
-        self.use_library('aggrid')
+        self.use_library(library_name)
 
     @staticmethod
     def from_pandas(df: 'pandas.DataFrame', *, theme: str = 'balham') -> AgGrid:

+ 7 - 7
nicegui/elements/chart.py

@@ -7,11 +7,11 @@ from ..element import Element
 register_vue_component('chart', Path(__file__).parent / 'chart.js')
 
 core_dependencies: List[Path] = []
-for path in sorted((Path(__file__).parent / 'lib' / 'highcharts').glob('*.js'), key=lambda p: p.stem):
-    register_library(path.stem, path)
-    core_dependencies.append(path)
-for path in sorted((Path(__file__).parent / 'lib' / 'highcharts' / 'modules').glob('*.js'), key=lambda p: p.stem):
-    register_library(path.stem, path)
+base = Path(__file__).parent / 'lib'
+for path in sorted((base / 'highcharts').glob('*.js'), key=lambda p: p.stem):
+    core_dependencies.append(register_library(path.relative_to(base)))
+for path in sorted((base / 'highcharts' / 'modules').glob('*.js'), key=lambda p: p.stem):
+    register_library(path.relative_to(base))
 
 
 class Chart(Element):
@@ -36,9 +36,9 @@ class Chart(Element):
         self._props['extras'] = extras
         self.use_component('chart')
         for dependency in core_dependencies:
-            self.use_library(dependency.stem)
+            self.use_library(dependency)
         for extra in extras:
-            self.use_library(extra)
+            self.use_library(f'highcharts/modules/{extra}.js')
 
     @property
     def options(self) -> Dict:

+ 2 - 2
nicegui/elements/joystick.py

@@ -6,7 +6,7 @@ from ..element import Element
 from ..events import GenericEventArguments, JoystickEventArguments, handle_event
 
 register_vue_component('joystick', Path(__file__).parent / 'joystick.vue')
-register_library('nipplejs', Path(__file__).parent / 'lib' / 'nipplejs' / 'nipplejs.js')
+library_name = register_library(Path('nipplejs') / 'nipplejs.js')
 
 
 class Joystick(Element):
@@ -28,7 +28,7 @@ class Joystick(Element):
         :param options: arguments like `color` which should be passed to the `underlying nipple.js library <https://github.com/yoannmoinet/nipplejs#options>`_
         """
         super().__init__('joystick')
-        self.use_library('nipplejs')
+        self.use_library(library_name)
         self._props['options'] = options
         self.active = False
 

+ 2 - 2
nicegui/elements/mermaid.py

@@ -4,7 +4,7 @@ from ..dependencies import register_library, register_vue_component
 from .mixins.content_element import ContentElement
 
 register_vue_component('mermaid', Path(__file__).parent / 'mermaid.js')
-register_library('mermaid', Path(__file__).parent / 'lib' / 'mermaid' / 'mermaid.esm.min.mjs', expose=True)
+library_name = register_library(Path('mermaid') / 'mermaid.esm.min.mjs', expose=True)
 
 
 class Mermaid(ContentElement):
@@ -20,7 +20,7 @@ class Mermaid(ContentElement):
         '''
         super().__init__(tag='mermaid', content=content)
         self.use_component('mermaid')
-        self.use_library('mermaid')
+        self.use_library(library_name)
 
     def on_content_change(self, content: str) -> None:
         self._props[self.CONTENT_PROP] = content.strip()

+ 2 - 2
nicegui/elements/plotly.py

@@ -7,7 +7,7 @@ from ..dependencies import register_library, register_vue_component
 from ..element import Element
 
 register_vue_component('plotly', Path(__file__).parent / 'plotly.vue')
-register_library('plotly', Path(__file__).parent / 'lib' / 'plotly' / 'plotly.min.js')
+library_name = register_library(Path('plotly') / 'plotly.min.js')
 
 
 class Plotly(Element):
@@ -28,7 +28,7 @@ class Plotly(Element):
                        a `dict` object with keys `data`, `layout`, `config` (optional).
         """
         super().__init__('plotly')
-        self.use_library('plotly')
+        self.use_library(library_name)
 
         self.figure = figure
         self.update()

+ 11 - 12
nicegui/elements/scene.py

@@ -10,12 +10,15 @@ from ..helpers import KWONLY_SLOTS
 from .scene_object3d import Object3D
 
 register_vue_component('scene', Path(__file__).parent / 'scene.js')
-register_library('three', Path(__file__).parent / 'lib' / 'three' / 'three.module.js', expose=True)
-register_library('CSS2DRenderer', Path(__file__).parent / 'lib' / 'three' / 'modules' / 'CSS2DRenderer.js', expose=True)
-register_library('CSS3DRenderer', Path(__file__).parent / 'lib' / 'three' / 'modules' / 'CSS3DRenderer.js', expose=True)
-register_library('OrbitControls', Path(__file__).parent / 'lib' / 'three' / 'modules' / 'OrbitControls.js', expose=True)
-register_library('STLLoader', Path(__file__).parent / 'lib' / 'three' / 'modules' / 'STLLoader.js', expose=True)
-register_library('tween', Path(__file__).parent / 'lib' / 'tween' / 'tween.umd.js')
+lib = Path('three')
+library_names = [
+    register_library(lib / 'three.module.js', expose=True),
+    register_library(lib / 'modules' / 'CSS2DRenderer.js', expose=True),
+    register_library(lib / 'modules' / 'CSS3DRenderer.js', expose=True),
+    register_library(lib / 'modules' / 'OrbitControls.js', expose=True),
+    register_library(lib / 'modules' / 'STLLoader.js', expose=True),
+    register_library(lib / 'tween' / 'tween.umd.js'),
+]
 
 
 @dataclass(**KWONLY_SLOTS)
@@ -83,12 +86,8 @@ class Scene(Element):
         self.on('init', self.handle_init)
         self.on('click3d', self.handle_click)
         self.use_component('scene')
-        self.use_library('three')
-        self.use_library('CSS2DRenderer')
-        self.use_library('CSS3DRenderer')
-        self.use_library('OrbitControls')
-        self.use_library('STLLoader')
-        self.use_library('tween')
+        for library_name in library_names:
+            self.use_library(library_name)
 
     def handle_init(self, e: GenericEventArguments) -> None:
         self.is_initialized = True

+ 7 - 6
nicegui/nicegui.py

@@ -44,13 +44,14 @@ def index(request: Request) -> Response:
     return globals.index_client.build_response(request)
 
 
-@app.get(f'/_nicegui/{__version__}' + '/library/{name}/{file}')
-def get_dependencies(name: str, file: str):
+@app.get(f'/_nicegui/{__version__}' + '/library/{name:path}')
+def get_dependencies(name: str):
     if name in libraries and libraries[name]['path'].exists():
-        filepath = Path(libraries[name]['path']).parent / file
-        if filepath.exists() and not filepath.is_dir():
-            return FileResponse(filepath, media_type='text/javascript')
-        return FileResponse(libraries[name]['path'], media_type='text/javascript')
+        return FileResponse(
+            libraries[name]['path'],
+            media_type='text/javascript',
+            headers={'Cache-Control': 'public, max-age=3600'}
+        )
     raise HTTPException(status_code=404, detail=f'dependency "{name}" not found')
 
 

+ 1 - 1
nicegui/templates/index.html

@@ -190,7 +190,7 @@
       async function loadDependencies(element) {
         for (const name of element['libraries']) {
           if (loaded_libraries.has(name)) continue;
-          await import(`{{ prefix | safe }}/_nicegui/{{version}}/library/${name}/include`);
+          await import(`{{ prefix | safe }}/_nicegui/{{version}}/library/${name}`);
           loaded_libraries.add(name);
         }
         for (const name of element['components']) {