diff --git a/packages/core/src/compiler/htmlBundler.test.ts b/packages/core/src/compiler/htmlBundler.test.ts index 195d133e0..8981c1ea5 100644 --- a/packages/core/src/compiler/htmlBundler.test.ts +++ b/packages/core/src/compiler/htmlBundler.test.ts @@ -267,24 +267,60 @@ describe("bundleToSingleHtml", () => { "compositions/scene.html": ``, - "shared/dist/vendor/powerglitch.min.js": `window.PowerGlitch = { glitch(){ return { startGlitch(){}, stopGlitch(){} }; } };`, - "shared/dist/index.js": `window.__HF_SHARED_TEST__ = "shared-runtime-loaded";`, + "vendor/effect-plugin.js": `window.PowerGlitch = { glitch(){ return { startGlitch(){}, stopGlitch(){} }; } };`, + "assets/scene-runtime.js": `window.__HF_SHARED_TEST__ = "shared-runtime-loaded";`, }); const bundled = await bundleToSingleHtml(dir); expect(bundled).toContain('__HF_SHARED_TEST__ = "shared-runtime-loaded"'); expect(bundled).toContain("window.PowerGlitch = { glitch()"); - expect(bundled).not.toContain('src="shared/dist/index.js"'); - expect(bundled).not.toContain('src="shared/dist/vendor/powerglitch.min.js"'); + expect(bundled).not.toContain('src="assets/scene-runtime.js"'); + expect(bundled).not.toContain('src="vendor/effect-plugin.js"'); + }); + + it("preserves local sub-composition script order before inline scene scripts", async () => { + const dir = makeTempProject({ + "index.html": ` + + + +
+
+
+ +`, + "compositions/scene.html": ``, + "assets/component-runtime.js": `window.__HF_COMPONENT_DEF__ = true; window.Component = { mount(){ window.__HF_COMPONENT_MOUNTED__ = true; } };`, + }); + + const bundled = await bundleToSingleHtml(dir); + const componentIndex = bundled.indexOf("__HF_COMPONENT_DEF__"); + const sceneIndex = bundled.indexOf("__HF_COMPONENT_CALL__"); + + expect(componentIndex).toBeGreaterThan(-1); + expect(sceneIndex).toBeGreaterThan(-1); + expect(componentIndex).toBeLessThan(sceneIndex); }); it("does not duplicate CDN scripts already present in the main document", async () => { diff --git a/packages/core/src/compiler/htmlBundler.ts b/packages/core/src/compiler/htmlBundler.ts index 69debaca2..f4442a955 100644 --- a/packages/core/src/compiler/htmlBundler.ts +++ b/packages/core/src/compiler/htmlBundler.ts @@ -718,12 +718,34 @@ export async function bundleToSingleHtml( }, }); const compStyleChunks: string[] = [...subCompResult.styles]; - const compScriptChunks: string[] = [...subCompResult.scripts]; - const compExternalScriptSrcs: string[] = [...subCompResult.externalScriptSrcs]; + const compScriptChunks: string[] = []; const compExternalLinks = [...subCompResult.externalLinks]; const compVariablesByComp: Record> = { ...subCompResult.variablesByComp, }; + const seenCompScriptSrcs = new Set(); + for (const scriptItem of subCompResult.scriptItems) { + if (scriptItem.kind === "inline") { + compScriptChunks.push(scriptItem.content); + continue; + } + const extSrc = scriptItem.src; + if (seenCompScriptSrcs.has(extSrc)) continue; + seenCompScriptSrcs.add(extSrc); + if (isRelativeUrl(extSrc)) { + const jsPath = safePath(projectDir, extSrc); + const js = jsPath ? safeReadFile(jsPath) : null; + if (js != null) { + compScriptChunks.push(js); + continue; + } + } + if (!document.querySelector(`script[src="${extSrc}"]`)) { + const extScript = document.createElement("script"); + extScript.setAttribute("src", extSrc); + document.body.appendChild(extScript); + } + } // Inline template compositions: inject