diff --git a/packages/core/src/compiler/htmlBundler.test.ts b/packages/core/src/compiler/htmlBundler.test.ts
index d41dfbd1c..0ee9eeaf7 100644
--- a/packages/core/src/compiler/htmlBundler.test.ts
+++ b/packages/core/src/compiler/htmlBundler.test.ts
@@ -125,6 +125,35 @@ describe("bundleToSingleHtml", () => {
expect(bundled).not.toContain("SECRET_MARKER_LEAKED");
});
+ it("bundles a sub-composition external script whose src contains a double quote", async () => {
+ // The external-script dedup interpolated src into a `script[src="..."]`
+ // selector unescaped, so a `"` in the URL (a quoted query param) built a
+ // malformed selector that threw in css-select and aborted the whole bundle.
+ // The sibling link[href] path already escapes; align the script path.
+ const quotedSrc = `https://cdn.example.com/lib.js?cb="x`;
+ const dir = makeTempProject({
+ "index.html": `
+
+
+
+`,
+ "compositions/scene.html": `
+
+
+
+`,
+ });
+
+ const bundled = await bundleToSingleHtml(dir);
+ // Does not throw, and the external script survives into the bundle.
+ expect(bundled).toContain(`cb=`);
+ });
+
it("produces a self-contained runtime script when no HYPERFRAME_RUNTIME_URL is set", async () => {
// Regression guard: hf#XXX. The bundler used to emit
// when no runtime URL was configured. An
diff --git a/packages/core/src/compiler/htmlBundler.ts b/packages/core/src/compiler/htmlBundler.ts
index 538f0632f..62ab48f9c 100644
--- a/packages/core/src/compiler/htmlBundler.ts
+++ b/packages/core/src/compiler/htmlBundler.ts
@@ -624,7 +624,7 @@ export interface BundleOptions {
*/
function ensureExternalScriptTag(doc: Document, src: string): void {
- if (doc.querySelector(`script[src="${src}"]`)) return;
+ if (doc.querySelector(`script${cssAttributeSelector("src", src)}`)) return;
const el = doc.createElement("script");
el.setAttribute("src", src);
doc.body.appendChild(el);
@@ -825,7 +825,7 @@ export async function bundleToSingleHtml(
continue;
}
}
- if (!document.querySelector(`script[src="${extSrc}"]`)) {
+ if (!document.querySelector(`script${cssAttributeSelector("src", extSrc)}`)) {
const extScript = document.createElement("script");
extScript.setAttribute("src", extSrc);
document.body.appendChild(extScript);
@@ -857,7 +857,7 @@ export async function bundleToSingleHtml(
const hostIdentity = hostIdentityByElement.get(host);
const runtimeCompId = hostIdentity?.runtimeCompositionId || compId;
const innerDoc = parseHTMLContent(templateHtml);
- const innerRoot = innerDoc.querySelector(`[data-composition-id="${compId}"]`);
+ const innerRoot = innerDoc.querySelector(cssAttributeSelector("data-composition-id", compId));
const authoredRootId = innerRoot?.getAttribute("id")?.trim() || null;
const runtimeScope = runtimeCompId
? cssAttributeSelector("data-composition-id", runtimeCompId)