Skip to content

Commit c2f97c7

Browse files
committed
repair hydration mismatches
1 parent edf31f1 commit c2f97c7

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

packages/svelte/src/internal/client/dom/blocks/svelte-html.js

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { render_effect, teardown } from '../../reactivity/effects.js';
1+
import { effect, render_effect, teardown } from '../../reactivity/effects.js';
2+
import { untrack } from '../../runtime.js';
23
import { set_attribute } from '../elements/attributes.js';
34
import { set_class } from '../elements/class.js';
45
import { hydrating } from '../hydration.js';
@@ -15,10 +16,10 @@ export function svelte_html(get_attributes) {
1516
// @ts-expect-error
1617
const current_setters = (node.__attributes_setters ??= {});
1718

18-
/** @type {Record<string, any>} */
19+
/** @type {Record<string, any>} Does _not_ contain event listeners, those are handled separately */
1920
let attributes;
2021

21-
render_effect(() => {
22+
const set_html_attributes = () => {
2223
attributes = get_attributes();
2324

2425
for (const name in attributes) {
@@ -29,9 +30,16 @@ export function svelte_html(get_attributes) {
2930
let value = attributes[name];
3031
current.push({ owner: self, value });
3132

32-
// Do nothing on initial render during hydration: If there are attribute duplicates, the last value
33-
// wins, which could result in needless hydration repairs from earlier values.
34-
if (hydrating) continue;
33+
// Defer hydration on initial render during hydration: If there are attribute duplicates, the last value
34+
// wins, so we wait until all values have been set to see if we're actually the last one that sets the value.
35+
if (hydrating) {
36+
effect(() => {
37+
if (current[current.length - 1].owner === self) {
38+
untrack(set_html_attributes);
39+
}
40+
});
41+
return;
42+
}
3543

3644
if (name === 'class') {
3745
// Avoid unrelated attribute changes from triggering class changes
@@ -42,7 +50,9 @@ export function svelte_html(get_attributes) {
4250
set_attribute(node, name, value);
4351
}
4452
}
45-
});
53+
};
54+
55+
render_effect(set_html_attributes);
4656

4757
teardown(() => {
4858
for (const name in attributes) {
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { test } from '../../test';
2+
3+
export default test({
4+
server_props: {
5+
lang: 'en'
6+
},
7+
8+
props: {
9+
lang: 'de'
10+
},
11+
12+
test(assert, target) {
13+
assert.htmlEqual(target.ownerDocument.documentElement.lang, 'de');
14+
}
15+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<script>
2+
let { lang } = $props();
3+
</script>
4+
5+
<svelte:html {lang} />

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy