in template l","item":"https://projects.agentabrams.com/p/dw-collections-viewer/c/f3e88a0"}]}
← back to Dw Collections Viewer
Fix HTML tokenizer breaking outer script — escape nested </script> in template literal
f3e88a09ef28fe38e6fa71ab4d13cd6fba575dff · 2026-05-06 19:47:36 -0700 · SteveStudio2
renderDetail() injects a giant template-literal HTML block via
innerHTML; that block contains a nested <script>(restore deploy-sort)</script>
helper. Browsers' HTML tokenizer doesn't respect JS template literals — when
it hits the inner </script>, it terminates the OUTER <script> block too.
Everything after that closing tag (including the outer template's closing
backtick) became raw HTML, leaving the main JS body unterminated:
'Unexpected end of input'. Page rendered shell only, no site cards.
Fix: split the open tag as <` + `script> and escape the close as <\/script>
inside the template literal. Tokenizer no longer sees a script boundary.
Verified via debate-team-fast (Claude + Kimi + Qwen3 all 3/3): correct fix.
Future refactor (ticket): move the inline restore script OUT of the template
literal entirely (data-attribute + DOMContentLoaded hook). Add a pre-commit
grep for unescaped </script> inside backtick template literals.
Files touched
Diff
commit f3e88a09ef28fe38e6fa71ab4d13cd6fba575dff
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 6 19:47:36 2026 -0700
Fix HTML tokenizer breaking outer script — escape nested </script> in template literal
renderDetail() injects a giant template-literal HTML block via
innerHTML; that block contains a nested <script>(restore deploy-sort)</script>
helper. Browsers' HTML tokenizer doesn't respect JS template literals — when
it hits the inner </script>, it terminates the OUTER <script> block too.
Everything after that closing tag (including the outer template's closing
backtick) became raw HTML, leaving the main JS body unterminated:
'Unexpected end of input'. Page rendered shell only, no site cards.
Fix: split the open tag as <` + `script> and escape the close as <\/script>
inside the template literal. Tokenizer no longer sees a script boundary.
Verified via debate-team-fast (Claude + Kimi + Qwen3 all 3/3): correct fix.
Future refactor (ticket): move the inline restore script OUT of the template
literal entirely (data-attribute + DOMContentLoaded hook). Add a pre-commit
grep for unescaped </script> inside backtick template literals.
---
public/index.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/public/index.html b/public/index.html
index b71c893..a4fcae1 100644
--- a/public/index.html
+++ b/public/index.html
@@ -918,7 +918,7 @@ function renderDetail() {
<button class="btn" onclick="renderSite()" ${assigned.length === 0 ? 'disabled' : ''}>Render now (live)</button>
<a class="btn" href="https://${s.domain}" target="_blank" style="text-decoration:none">Open site ↗</a>
</div>
- <script>
+ <` + `script>
// Restore saved deploy sort. Precedence: per-site rules.sort (server) > localStorage > default.
(function(){
const sel = document.getElementById('deploySortSel');
@@ -928,7 +928,7 @@ function renderDetail() {
const v = perSite || fallback;
if (v && Array.from(sel.options).some(o => o.value === v)) sel.value = v;
})();
- </script>
+ <\/script>
`;
// Hydrate the products slider after the detail HTML is in the DOM.
renderProductsSlider();
← a0cea68 save+deploy: persist chosen sort to per-site rules; UI pre-p
·
back to Dw Collections Viewer
·
dw-collections-viewer: stale-products pill (>30 days mtime) 15a2c8f →