fix: repair `href` attribute mismatches (#13032)

* fix: repair `href` attribute mismatches

The reasoning in #9662 turns out to be false: While it's true that the href would resolve to the same URL on the initial page, once you're doing a client-side navigation to a URL at a different depth, the relative path would now point to the wrong location. Therefore we need to repair href hydration mismatches

fixes https://github.com/sveltejs/kit/issues/12254

* remove test

* Revert "remove test"

This reverts commit fa43304329.

* fix test

* remove comment, since the rationale for skipping the attributes in question is covered by the one immediately below

* fix

* add test for <a> specifically

---------

Co-authored-by: Rich Harris <rich.harris@vercel.com>
pull/13036/head
Simon H 1 year ago committed by GitHub
parent c4b721584a
commit e03dae95da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: repair `href` attribute mismatches

@ -89,7 +89,11 @@ export function set_attribute(element, attribute, value, skip_warning) {
if (hydrating) {
attributes[attribute] = element.getAttribute(attribute);
if (attribute === 'src' || attribute === 'href' || attribute === 'srcset') {
if (
attribute === 'src' ||
attribute === 'srcset' ||
(attribute === 'href' && element.nodeName === 'LINK')
) {
if (!skip_warning) {
check_src_in_dev_hydration(element, attribute, value);
}
@ -388,7 +392,7 @@ function check_src_in_dev_hydration(element, attribute, value) {
w.hydration_attribute_changed(
attribute,
element.outerHTML.replace(element.innerHTML, '...'),
element.outerHTML.replace(element.innerHTML, element.innerHTML && '...'),
String(value)
);
}

@ -10,10 +10,10 @@ export default test({
},
test(assert, target) {
assert.equal(target.querySelector('a')?.getAttribute('href'), '/bar');
assert.equal(target.querySelector('link')?.getAttribute('href'), '/bar');
},
errors: [
'The `href` attribute on `<a href="/bar">...</a>` changed its value between server and client renders. The client value, `/foo`, will be ignored in favour of the server value'
'The `href` attribute on `<link href="/bar">` changed its value between server and client renders. The client value, `/foo`, will be ignored in favour of the server value'
]
});

@ -2,4 +2,4 @@
let { browser } = $props();
</script>
<a href={browser ? '/foo': '/bar'}>foo</a>
<link href={browser ? '/foo' : '/bar'} />

@ -12,6 +12,6 @@ export default test({
assert.htmlEqual(target.innerHTML, '<img src="server.jpg" alt="">');
},
errors: [
'The `src` attribute on `...<img src="server.jpg" alt="">` changed its value between server and client renders. The client value, `client.jpg`, will be ignored in favour of the server value'
'The `src` attribute on `<img src="server.jpg" alt="">` changed its value between server and client renders. The client value, `client.jpg`, will be ignored in favour of the server value'
]
});

@ -0,0 +1,11 @@
import { test } from '../../test';
export default test({
server_props: {
browser: false
},
props: {
browser: true
}
});

@ -0,0 +1,5 @@
<script>
let { browser } = $props();
</script>
<a href={browser ? '/foo' : '/bar'}>foo</a>
Loading…
Cancel
Save