diff --git a/packages/sdk-components-react/src/html-embed.tsx b/packages/sdk-components-react/src/html-embed.tsx index a217a9a2c87f..ef9d8aa3e2f1 100644 --- a/packages/sdk-components-react/src/html-embed.tsx +++ b/packages/sdk-components-react/src/html-embed.tsx @@ -15,9 +15,7 @@ export const __testing__ = { scriptTestIdPrefix: "client-", }; -const insertScript = ( - sourceScript: HTMLScriptElement -): Promise => { +const insertScript = (sourceScript: HTMLScriptElement): Promise => { return new Promise((resolve, reject) => { const script = document.createElement("script"); const hasSrc = sourceScript.hasAttribute("src"); @@ -35,7 +33,7 @@ const insertScript = ( if (hasSrc) { script.addEventListener("load", () => { - resolve(script); + resolve(); }); script.addEventListener("error", reject); } else { @@ -46,21 +44,48 @@ const insertScript = ( // Run the callback immediately for inline scripts. if (hasSrc === false) { - resolve(script); + resolve(); } }); }; -type ScriptTask = () => Promise; +type ScriptTask = () => Promise; + +/** + * We want to execute scripts from all embeds sequentially to preserve execution order. + */ +const syncTasksQueue: ScriptTask[] = []; +let processing = false; + +const processSyncTasks = async (syncTasks: ScriptTask[]) => { + syncTasksQueue.push(...syncTasks); + + // await 1 tick so tasks from all HTMLEmbeds are added to the queue + await Promise.resolve(); + + if (processing) { + return; + } + + processing = true; + + while (syncTasksQueue.length > 0) { + const task = syncTasksQueue.shift()!; + await task(); + } + + processing = false; +}; // Inspiration https://ghinda.net/article/script-tags -const execute = async (container: HTMLElement) => { +const execute = (container: HTMLElement) => { const scripts = container.querySelectorAll("script"); const syncTasks: Array = []; const asyncTasks: Array = []; scripts.forEach((script) => { const tasks = script.hasAttribute("async") ? asyncTasks : syncTasks; + tasks.push(() => { return insertScript(script); }); @@ -71,10 +96,7 @@ const execute = async (container: HTMLElement) => { task(); } - // Insert the script tags sequentially to preserve execution order. - for (const task of syncTasks) { - await task(); - } + processSyncTasks(syncTasks); }; type ChildProps = {