Skip to content

fix(ssr,react-ssr,preact-ssr,svelte-ssr): escape head values and the dehydrated snapshot in the rendered html - #239

Merged
dangreen merged 1 commit into
mainfrom
fix/ssr-html-escaping
Sep 8, 2026
Merged

dangreen merged 1 commit into
mainfrom
fix/ssr-html-escaping

Conversation

@dangreen

@dangreen dangreen commented Sep 8, 2026 •

Copy link
Copy Markdown
Member

Why

The SSR renderers built the document from raw strings: <title> (and lang / dir in the Svelte renderer) were interpolated as is, headDescriptorToHtml escaped attribute quotes with a backslash instead of an entity, and dehydratedScript inlined the JSON.stringify output, so a dehydrated value containing </script> closed the tag and the rest of the value was parsed as markup.

What

  • @nano_kit/ssr/renderer: new escapeHtml (&, <, >, ") that returns strings without special characters as is and otherwise scans with charCodeAt; headDescriptorToHtml uses it for attribute values; dehydratedScript escapes < as \u003c.
  • React and Preact renderers escape the title; the Svelte renderer escapes the title, lang and dir (there the whole document is a template string).
  • Tests: escapeHtml, attribute values (static, reactive, empty), raw script code, the </script> case for dehydratedScript, and title escaping in all three adapters (plus lang for Svelte).

oxlint, vitest and tsc --noEmit pass in ssr, react-ssr, preact-ssr and svelte-ssr.

@codecov

codecov Bot commented Sep 8, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 83.32%. Comparing base (65da70d) to head (1581a66).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #239      +/-   ##
==========================================
+ Coverage   83.05%   83.32%   +0.26%     
==========================================
  Files          98       98              
  Lines        2532     2554      +22     
  Branches      545      549       +4     
==========================================
+ Hits         2103     2128      +25     
+ Misses        315      314       -1     
+ Partials      114      112       -2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…dehydrated snapshot in the rendered html

The renderers built the document from raw strings: `<title>` (and `lang` / `dir` in the Svelte renderer) were interpolated as is, `headDescriptorToHtml` escaped attribute quotes with a backslash, and `dehydratedScript` inlined the `JSON.stringify` output, so a dehydrated value containing `</script>` closed the tag.

`@nano_kit/ssr/renderer` now exports `escapeHtml`, used for head attribute values and titles, and `dehydratedScript` escapes `<` as `\u003c`.
@dangreen
dangreen force-pushed the fix/ssr-html-escaping branch from 2a8cfaf to 1581a66 Compare September 8, 2026 13:12
@dangreen
dangreen merged commit 60eefe2 into main Sep 8, 2026
10 checks passed
@dangreen
dangreen deleted the fix/ssr-html-escaping branch September 8, 2026 13:26
@github-actions github-actions Bot mentioned this pull request Sep 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant