Mercurial > libervia-web
comparison libervia/web/server/tasks/implicit/task_js_modules.py @ 1570:038d4bfdd967
server (tasks/JS modules): add new way to generate modules + support of CSS files
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 22 Nov 2023 16:31:32 +0100 |
parents | eb00d593801d |
children | d07838fc9d99 |
comparison
equal
deleted
inserted
replaced
1569:54ba0f74a488 | 1570:038d4bfdd967 |
---|---|
42 for module_name, module_data in brython_map.items(): | 42 for module_name, module_data in brython_map.items(): |
43 log.debug(f"generating mapping for {module_name}") | 43 log.debug(f"generating mapping for {module_name}") |
44 if ' ' in module_name: | 44 if ' ' in module_name: |
45 raise ValueError( | 45 raise ValueError( |
46 f"module {module_name!r} has space(s), it must not!") | 46 f"module {module_name!r} has space(s), it must not!") |
47 module_path = js_modules_path / f"{module_name}.py" | 47 module_python_name = module_name.replace(".", "_").replace("-", "_") |
48 if module_python_name != module_name: | |
49 log.info("{module_python_name!r} will be used as python module name") | |
50 module_path = js_modules_path / f"{module_python_name}.py" | |
48 if isinstance(module_data, str): | 51 if isinstance(module_data, str): |
49 module_data = {'path': module_data} | 52 module_data = {'path': [module_data]} |
50 try: | 53 try: |
51 js_path = module_data.pop('path') | 54 js_paths = module_data.pop('path') |
52 except KeyError: | 55 except KeyError: |
53 raise ValueError( | 56 raise ValueError( |
54 f'module data for {module_name} must have a "path" key') | 57 f'module data for {module_name} must have a "path" key') |
55 module_data['path'] = Path('node_modules') / js_path.strip(' /') | 58 if isinstance(js_paths, str): |
56 export = module_data.get('export') or [module_name] | 59 js_paths = [js_paths] |
57 export_objects = '\n'.join(f'{e} = window.{e}' for e in export) | 60 module_data['path'] = [ |
58 extra_kwargs = {"build_dir": C.BUILD_DIR} | 61 Path('node_modules') / js_path.strip(' /') for js_path in js_paths |
62 ] | |
63 to_export = module_data.get("export", [module_name]) | |
64 if isinstance(to_export, str): | |
65 to_export = to_export.split(",") | |
66 to_export = [e.strip() for e in to_export] | |
67 | |
68 init_code = [] | |
69 | |
70 # CSS if any | |
71 css_to_load = module_data.get("css") | |
72 if css_to_load: | |
73 if isinstance(css_to_load, str): | |
74 css_to_load = [css_to_load] | |
75 | |
76 add_styles_lines = [] | |
77 for css_path in css_to_load: | |
78 normalized_css_path = Path("node_modules") / css_path.strip(" /") | |
79 css_href = Path("/").joinpath(C.BUILD_DIR, normalized_css_path) | |
80 style_tag = ( | |
81 f'<link rel="stylesheet" type="text/css" href="{css_href}">' | |
82 ) | |
83 add_style_code = ( | |
84 'document.head.insertAdjacentHTML(' | |
85 '"beforeend", ' | |
86 f"'{style_tag}')" | |
87 ) | |
88 add_styles_lines.append(add_style_code) | |
89 | |
90 add_styles = "\n".join(add_styles_lines) | |
91 else: | |
92 add_styles = "" | |
59 | 93 |
60 with module_path.open('w') as f: | 94 with module_path.open('w') as f: |
61 f.write(f"""\ | 95 browser_imports = ["aio", "document"] |
62 #!/usr/bin/env python3 | 96 modules_import = [] |
63 from browser import window, load | 97 script_paths = [ |
64 {module_data.get('extra_import', '')} | 98 str(Path('/').joinpath(C.BUILD_DIR, path)) |
99 for path in module_data["path"] | |
100 ] | |
101 import_type = module_data.get('import_type', "load") | |
102 if import_type == 'module': | |
103 modules_import.append('javascript') | |
104 modules_import.append('proxy') | |
105 callback_function_name = f"on_{module_python_name}_loaded" | |
106 declare_obj = "\n".join(f"{e} = proxy.JSProxy()" for e in to_export) | |
107 export_str = "\n ".join(f"{e}.js_module=module.{e}" for e in to_export) | |
108 load_js_libraries = ( | |
109 f"\n{declare_obj}\n\n" | |
110 f"def {callback_function_name}(module):\n" | |
111 f" {export_str}\n" | |
112 f" loaded.set_result(True)\n\n" | |
113 f"javascript.import_modules({script_paths}, {callback_function_name})\n" | |
114 ) | |
115 elif import_type == 'script': | |
116 browser_imports.append("window") | |
117 script_tags = [ | |
118 f"<script src='{src}'></script>" for src in script_paths | |
119 ] | |
120 load_js_libraries = "\n".join( | |
121 f'document.head.insertAdjacentHTML("beforeend", "{tag}")' | |
122 for tag in script_tags | |
123 ) | |
124 init_code.append('\n'.join(f'{e} = window.{e}' for e in to_export)) | |
125 init_code.append("loaded.set_result(True)") | |
126 elif import_type == "load": | |
127 browser_imports.append("load") | |
128 browser_imports.append("window") | |
129 load_calls = [f'load("{src}")' for src in script_paths] | |
130 load_js_libraries = "\n".join(load_calls) | |
131 init_code.append('\n'.join(f'{e} = window.{e}' for e in to_export)) | |
132 init_code.append("loaded.set_result(True)") | |
133 else: | |
134 raise ValueError("Invalid import type: {import_type!r}") | |
65 | 135 |
66 load("{Path('/').joinpath(C.BUILD_DIR, module_data['path'])}") | 136 extra_init = module_data.get("extra_init") |
67 {export_objects} | 137 if extra_init is not None: |
68 {module_data.get('extra_init', '').format(**extra_kwargs)} | 138 if not isinstance(extra_init, str): |
69 """) | 139 raise ValueError(f"Invalid extra_init: {extra_init!r}") |
140 init_code.append( | |
141 extra_init.format( | |
142 build_dir = C.BUILD_DIR | |
143 ) | |
144 ) | |
145 | |
146 init_code_str = "\n".join(init_code) | |
147 imports = [f"from browser import {', '.join(browser_imports)}"] | |
148 for module in modules_import: | |
149 imports.append(f"import {module}") | |
150 imports_str = "\n".join(imports) | |
151 | |
152 f.write( | |
153 "#!/usr/bin/env python3\n" | |
154 f"{imports_str}\n\n" | |
155 f"loaded = aio.Future()\n" | |
156 f"{add_styles}\n" | |
157 f"{load_js_libraries}\n" | |
158 f"{init_code_str}" | |
159 ) |