fix(html): hydration mismatch detection ignores <script> elements
Server pages legitimately carry scripts (state serialization, analytics) that are spent by hydration time and that client views never render — they are noise to the detector, and morph dropping them is harmless. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014NgfSjHE11oFpoSnLVKLXd
This commit is contained in:
co-authored by
Claude Fable 5
parent
ce8fedee0b
commit
d755af5ca0
@@ -87,12 +87,15 @@ function firstDifference (a, b, path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// child nodes that matter for comparison: everything except
|
// child nodes that matter for comparison: everything except
|
||||||
// whitespace-only text nodes
|
// whitespace-only text nodes and <script> elements — server pages
|
||||||
|
// legitimately carry scripts (state serialization, analytics) that are
|
||||||
|
// already spent by hydration time and that client views never render
|
||||||
function significant (childNodes) {
|
function significant (childNodes) {
|
||||||
const out = []
|
const out = []
|
||||||
for (let i = 0; i < childNodes.length; i++) {
|
for (let i = 0; i < childNodes.length; i++) {
|
||||||
const node = childNodes[i]
|
const node = childNodes[i]
|
||||||
if (node.nodeType === 3 && !node.nodeValue.trim()) continue
|
if (node.nodeType === 3 && !node.nodeValue.trim()) continue
|
||||||
|
if (node.nodeType === 1 && node.nodeName === 'SCRIPT') continue
|
||||||
out.push(node)
|
out.push(node)
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
|
|||||||
@@ -67,6 +67,18 @@ test('child count mismatches are reported', () => {
|
|||||||
assert.strictEqual(reported.reason, 'children')
|
assert.strictEqual(reported.reason, 'children')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('server-only <script> elements are not reported as mismatches', () => {
|
||||||
|
// server pages carry state/analytics scripts the client never renders;
|
||||||
|
// they are spent by hydration time (morph may drop them — harmless)
|
||||||
|
const wrap = document.createElement('div')
|
||||||
|
wrap.innerHTML = '<div><h1>hi</h1><script>window.x=1</script></div>'
|
||||||
|
const server = wrap.firstChild
|
||||||
|
const client = html`<div><h1>hi</h1></div>`
|
||||||
|
let reported = null
|
||||||
|
hydrate(server, client, { onMismatch: (d) => { reported = d } })
|
||||||
|
assert.strictEqual(reported, null)
|
||||||
|
})
|
||||||
|
|
||||||
test('mismatch detection is optional and hydrate still morphs without it', () => {
|
test('mismatch detection is optional and hydrate still morphs without it', () => {
|
||||||
const server = html`<p>old</p>`
|
const server = html`<p>old</p>`
|
||||||
const client = html`<p>new</p>`
|
const client = html`<p>new</p>`
|
||||||
|
|||||||
Reference in New Issue
Block a user