mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-03 23:03:09 +00:00
fix(engine): inject sub-composition variables on the render path (#2066)
render left window.__hyperframes.getVariables() empty inside every
sub-composition mounted via data-composition-src, so each instance rendered
its declared JS defaults instead of the per-instance data-variable-values.
preview/snapshot injected them correctly, so the composition looked right in
every authoring/QA surface and then rendered wrong content silently (exit 0).
Any template-library workflow (reusable sub-comp scenes parametrized per
video) shipped placeholder/default text in the final MP4.
The plumbing already existed on main: htmlCompiler passes
readVariableDefaults/parseHostVariables and populates result.variablesByComp,
and the CSS-custom-property path (emitRootCompositionVariableStyles) reaches
the render. But the render compiler emitted only the CSS vars and never the
JS table window.__hfVariablesByComp that the scoped getVariables reads, while
the preview bundler (htmlBundler) did -- so getVariables() returned {} only
during render.
Fix, so the paths cannot drift again: buildVariablesByCompScript, colocated
with the reader in compositionScoping.ts and shared by both compile paths.
htmlBundler now calls it instead of an inline string; htmlCompiler injects it
before the inlined sub-comp scripts, using the already-populated
result.variablesByComp.
Verified end-to-end: a sub-comp painting its background from a color variable
now renders the injected value under render, matching snapshot; previously it
rendered the default. 3 new producer tests; 89 htmlCompiler + core-compiler
tests pass.
Closes #2064.
This commit is contained in:
@@ -523,3 +523,24 @@ ${source.replace(/<\/(script)/gi, "<\\/$1")}
|
||||
export function wrapInlineScriptWithErrorBoundary(source: string, errorLabel: string): string {
|
||||
return `(function(){ try { Function(${JSON.stringify(source)}).call(window); } catch (_err) { console.error(${JSON.stringify(errorLabel)}, _err); } })();`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the statement that populates `window.__hfVariablesByComp` — the table
|
||||
* the scoped `getVariables` above reads. Returns `null` when there are no
|
||||
* per-instance values.
|
||||
*
|
||||
* The WRITER lives next to the READER (the scoped `getVariables` in
|
||||
* `wrapScopedCompositionScript`) on purpose: every compile path that wraps the
|
||||
* reader MUST also emit this writer before the sub-comp scripts run. The
|
||||
* render compiler (`htmlCompiler`) inlined the reader scripts but never emitted
|
||||
* the writer while the preview bundler (`htmlBundler`) did, so
|
||||
* `getVariables()` returned `{}` only during render — parametrized sub-comps
|
||||
* silently shipped blank/default text in the final MP4 while snapshot QA passed
|
||||
* (issue #2064). Both callers now share this one builder so they can't drift.
|
||||
*/
|
||||
export function buildVariablesByCompScript(
|
||||
variablesByComp: Record<string, Record<string, unknown>>,
|
||||
): string | null {
|
||||
if (!variablesByComp || Object.keys(variablesByComp).length === 0) return null;
|
||||
return `window.__hfVariablesByComp = Object.assign({}, window.__hfVariablesByComp || {}, ${JSON.stringify(variablesByComp)});`;
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
} from "./htmlDocument";
|
||||
// rewriteSubCompPaths functions are used by inlineSubCompositions (shared module)
|
||||
import {
|
||||
buildVariablesByCompScript,
|
||||
scopeCssToComposition,
|
||||
wrapInlineScriptWithErrorBoundary,
|
||||
wrapScopedCompositionScript,
|
||||
@@ -939,10 +940,9 @@ export async function bundleToSingleHtml(
|
||||
style.textContent = compStyleChunks.join("\n\n");
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
if (Object.keys(compVariablesByComp).length > 0) {
|
||||
compScriptChunks.unshift(
|
||||
`window.__hfVariablesByComp = Object.assign({}, window.__hfVariablesByComp || {}, ${JSON.stringify(compVariablesByComp)});`,
|
||||
);
|
||||
const variablesByCompScript = buildVariablesByCompScript(compVariablesByComp);
|
||||
if (variablesByCompScript) {
|
||||
compScriptChunks.unshift(variablesByCompScript);
|
||||
}
|
||||
if (compScriptChunks.length) {
|
||||
const compScript = document.createElement("script");
|
||||
|
||||
@@ -52,7 +52,11 @@ export {
|
||||
} from "./staticGuard";
|
||||
|
||||
// Composition isolation helpers
|
||||
export { scopeCssToComposition, wrapScopedCompositionScript } from "./compositionScoping";
|
||||
export {
|
||||
buildVariablesByCompScript,
|
||||
scopeCssToComposition,
|
||||
wrapScopedCompositionScript,
|
||||
} from "./compositionScoping";
|
||||
|
||||
// Sub-composition inlining (shared between bundler and producer)
|
||||
export {
|
||||
|
||||
Reference in New Issue
Block a user