Skip to content

Commit

Permalink
feat: ignore href when hydrating (#9662)
Browse files Browse the repository at this point in the history
* ignore href when hydrating

* remove unused export keyword

---------

Co-authored-by: Rich Harris <[email protected]>
  • Loading branch information
Rich-Harris and Rich-Harris authored Nov 27, 2023
1 parent da1aa7c commit 9c44fd7
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 22 deletions.
5 changes: 5 additions & 0 deletions .changeset/slimy-clouds-talk.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'svelte': patch
---

feat: ignore href attributes when hydrating
43 changes: 21 additions & 22 deletions packages/svelte/src/internal/client/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -2532,6 +2532,7 @@ export function attr(dom, attribute, value) {
// (we can't just compare the strings as they can be different between client and server but result in the
// same url, so we would need to create hidden anchor elements to compare them)
attribute !== 'src' &&
attribute !== 'href' &&
attribute !== 'srcset')
) {
if (value === null) {
Expand All @@ -2550,7 +2551,7 @@ let src_url_equal_anchor;
* @param {string} url
* @returns {boolean}
*/
export function src_url_equal(element_src, url) {
function src_url_equal(element_src, url) {
if (element_src === url) return true;
if (!src_url_equal_anchor) {
src_url_equal_anchor = document.createElement('a');
Expand All @@ -2566,13 +2567,13 @@ function split_srcset(srcset) {
}

/**
* @param {HTMLSourceElement | HTMLImageElement} element_srcset
* @param {HTMLSourceElement | HTMLImageElement} element
* @param {string | undefined | null} srcset
* @returns {boolean}
*/
export function srcset_url_equal(element_srcset, srcset) {
const element_urls = split_srcset(element_srcset.srcset);
const urls = split_srcset(srcset || '');
export function srcset_url_equal(element, srcset) {
const element_urls = split_srcset(element.srcset);
const urls = split_srcset(srcset ?? '');

return (
urls.length === element_urls.length &&
Expand All @@ -2595,22 +2596,20 @@ export function srcset_url_equal(element_srcset, srcset) {
* @param {string | null} value
*/
function check_src_in_dev_hydration(dom, attribute, value) {
if (current_hydration_fragment !== null && (attribute === 'src' || attribute === 'srcset')) {
if (
(attribute === 'src' && !src_url_equal(dom.getAttribute('src') || '', value || '')) ||
(attribute === 'srcset' &&
!srcset_url_equal(/** @type {HTMLImageElement | HTMLSourceElement} */ (dom), value || ''))
) {
// eslint-disable-next-line no-console
console.error(
'Detected a src/srcset attribute value change during hydration. This will not be repaired during hydration, ' +
'the src/srcset value that came from the server will be used. Related element:',
dom,
' Differing value:',
value
);
}
}
if (!current_hydration_fragment) return;
if (attribute !== 'src' && attribute !== 'href' && attribute !== 'srcset') return;

if (attribute === 'srcset' && srcset_url_equal(dom, value)) return;
if (src_url_equal(dom.getAttribute(attribute) ?? '', value ?? '')) return;

// eslint-disable-next-line no-console
console.error(
`Detected a ${attribute} attribute value change during hydration. This will not be repaired during hydration, ` +
`the ${attribute} value that came from the server will be used. Related element:`,
dom,
' Differing value:',
value
);
}

/**
Expand Down Expand Up @@ -2778,7 +2777,7 @@ export function spread_attributes(dom, prev, attrs, lowercase_attributes, css_ha
if (
current_hydration_fragment === null ||
// @ts-ignore see attr method for an explanation of src/srcset
(dom[name] !== value && name !== 'src' && name !== 'srcset')
(dom[name] !== value && name !== 'src' && name !== 'href' && name !== 'srcset')
) {
// @ts-ignore
dom[name] = value;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!--ssr:0--><a href="/bar">foo</a><!--ssr:0-->
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { test } from '../../test';

export default test({
test(assert, target) {
assert.equal(target.querySelector('a')?.getAttribute('href'), '/bar');
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script>
let browser = typeof window !== 'undefined';
</script>

<a href={browser ? '/foo': '/bar'}>foo</a>

1 comment on commit 9c44fd7

@vercel
Copy link

@vercel vercel bot commented on 9c44fd7 Nov 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

svelte-5-preview – ./sites/svelte-5-preview

svelte-5-preview.vercel.app
svelte-5-preview-svelte.vercel.app
svelte-octane.vercel.app
svelte-5-preview-git-main-svelte.vercel.app

Please sign in to comment.