diff --git a/solara/server/esm.py b/solara/server/esm.py index e5f29cb23..bbae33036 100644 --- a/solara/server/esm.py +++ b/solara/server/esm.py @@ -2,15 +2,22 @@ # in the future, we may want to move the esm features of ipyreact # into a separate package, and then we can import it unconditionally import logging +import threading +from collections import defaultdict from pathlib import Path from typing import Dict, List, Tuple, Union import ipyreact.importmap import ipyreact.module +from solara.server import kernel_context + logger = logging.getLogger("solara.server.esm") +lock = threading.Lock() _modules: Dict[str, Tuple[Union[str, Path], List[str]]] = {} +_modules_added_per_kernel: Dict[str, Dict[str, ipyreact.module.Module]] = defaultdict(dict) +_import_map_per_kernel: Dict[str, ipyreact.importmap.ImportMap] = {} # in solara server, we'll monkey patch ipyreact.module with this @@ -29,10 +36,20 @@ def get_module_names(): def create_modules(): + kernel_id = kernel_context.get_current_context().id + _modules_added = _modules_added_per_kernel[kernel_id] logger.info("define modules %s", _modules) widgets = {} - for name, (module, dependencies) in _modules.items(): - widgets[name] = create_module(name, module, dependencies=dependencies) + with lock: + for name, (module, dependencies) in _modules.items(): + if name not in _modules_added: + _modules_added[name] = create_module(name, module, dependencies=dependencies) + logger.info("create module %s %s %s", name, module, dependencies) + else: + _modules_added[name].code = module if not isinstance(module, Path) else module.read_text(encoding="utf8") + _modules_added[name].dependencies = dependencies + logger.info("update module %s %s %s", name, module, dependencies) + widgets[name] = _modules_added[name] return widgets @@ -41,5 +58,12 @@ def create_module(name, module: Union[str, Path], dependencies: List[str]): def create_import_map(): - logger.info("create import map %s", ipyreact.importmap._effective_import_map) - return ipyreact.importmap.ImportMap(import_map=ipyreact.importmap._effective_import_map) + kernel_id = kernel_context.get_current_context().id + with lock: + if kernel_id not in _import_map_per_kernel: + _import_map_per_kernel[kernel_id] = ipyreact.importmap.ImportMap(import_map=ipyreact.importmap._effective_import_map) + logger.info("create import map %s", ipyreact.importmap._effective_import_map) + else: + _import_map_per_kernel[kernel_id].import_map = ipyreact.importmap._effective_import_map + logger.info("update import map %s", ipyreact.importmap._effective_import_map) + return