fix: defer DOM insertion until module imports resolve in component loader
Body nodes (containing Alpine x-data directives) were appended to the DOM immediately during the import loop, while <script type="module"> imports were awaited afterward. Alpine's MutationObserver would evaluate x-data expressions before the module had registered its store, causing "Cannot convert undefined or null to object" errors. Collect body nodes into a buffer and append them only after Promise.all(loadPromises) resolves, ensuring stores are registered before Alpine processes the DOM.
Alessandro committed
Mar 17, 2026 at 16:33 UTC
37d94433246e3e13908081b07b595e117ad51aba
1 file changed
+6
-2
webui/js/components.js
+6
-2
@@ -57,6 +57,7 @@ export async function importComponent(path, targetElement) {
57
];
58
59
const loadPromises = [];
60
+ const deferredNodes = [];
61
let blobCounter = 0;
62
63
for (const node of allNodes) {
@@ -156,14 +157,17 @@ export async function importComponent(path, targetElement) {
157
158
targetElement.appendChild(clone);
159
} else {
159
- const clone = node.cloneNode(true);
160
- targetElement.appendChild(clone);
160
+ deferredNodes.push(node.cloneNode(true));
161
}
162
}
163
164
// Wait for all tracked external scripts/styles to finish loading
165
await Promise.all(loadPromises);
166
167
+ for (const deferred of deferredNodes) {
168
+ targetElement.appendChild(deferred);
169
+ }
170
+
171
// Remove loading indicator
172
const loadingEl = targetElement.querySelector(':scope > .loading');
173
if (loadingEl) {