Await cached component module imports
Ensure x-component loading awaits cached dynamic import promises before appending deferred markup, matching first-load behavior and preventing Alpine bindings from running before imported stores register. Document the loader contract in the WebUI JS DOX notes.
Alessandro committed
Jul 8, 2026 at 20:53 UTC
a7255d97734abe511f04f6ffa4b6aa076270d2bd
2 files changed
+3
-2
webui/js/AGENTS.md
+1
@@ -37,6 +37,7 @@
37
- Keep extension loader cache keys and extension point names stable for plugins.
38
- HTML extension loading turns discovered HTML files into `<x-component>` tags; JavaScript extensions must export a default function.
39
- `<x-component>` loading must process component `style`, `script`, and stylesheet-link assets only once, even when a component keeps its scoped `<style>` inside `<body>`.
40
+- Every `<x-component>` instance must await cached module-load promises before markup is appended so Alpine bindings only run after imported stores exist.
41
- Frontend extension hooks such as `confirm_dialog_after_render` and `get_tool_message_handler` must preserve their mutable context contracts.
42
- Sanitize or safely render user/model-provided HTML and markdown.
43
- Do not expose secrets in localStorage, console logs, URLs, or WebSocket payloads.
webui/js/components.js
+2
-2
@@ -79,8 +79,8 @@ export async function importComponent(path, targetElement) {
79
if (!componentCache[resolvedUrl]) {
80
const modulePromise = import(resolvedUrl);
81
componentCache[resolvedUrl] = modulePromise;
82
- loadPromises.push(modulePromise);
82
}
83
+ loadPromises.push(componentCache[resolvedUrl]);
84
} else {
85
const virtualUrl = `${componentUrl.replaceAll(
86
"/",
@@ -122,8 +122,8 @@ export async function importComponent(path, targetElement) {
122
.finally(() => URL.revokeObjectURL(blobUrl));
123
124
componentCache[virtualUrl] = modulePromise;
125
- loadPromises.push(modulePromise);
125
}
126
+ loadPromises.push(componentCache[virtualUrl]);
127
}
128
} else {
129
// Non-module script