From 5b4356c9b3fc2a99fed50268d02d1f13192d7b0a Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Thu, 29 Jun 2023 11:35:08 +0200 Subject: [PATCH] this should do it --- packages/svelte/src/runtime/internal/utils.js | 13 ++++- packages/svelte/test/utils/utils.test.js | 51 ++++++++++++++++++- 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/packages/svelte/src/runtime/internal/utils.js b/packages/svelte/src/runtime/internal/utils.js index 846328bf05..2ca4b831f6 100644 --- a/packages/svelte/src/runtime/internal/utils.js +++ b/packages/svelte/src/runtime/internal/utils.js @@ -74,9 +74,11 @@ let src_url_equal_anchor; * @returns {boolean} */ export 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'); } + // This is actually faster than doing URL(..).href src_url_equal_anchor.href = url; return element_src === src_url_equal_anchor.href; } @@ -89,7 +91,7 @@ export function src_url_equal(element_src, url) { export function srcset_url_equal(element_srcset, srcset) { /** @param {string} _srcset */ function split(_srcset) { - return _srcset.split(',').map((src) => src.trim().split(' ')[0]); + return _srcset.split(',').map((src) => src.trim().split(' ').filter(Boolean)); } const element_urls = split(element_srcset.srcset); @@ -97,7 +99,14 @@ export function srcset_url_equal(element_srcset, srcset) { return ( urls.length === element_urls.length && - urls.every((url, i) => src_url_equal(element_urls[i], url)) + urls.every( + ([url, width], i) => + width === element_urls[i][1] && + // We need to test both ways because Vite/imagetools (but not other tools) will create an absolute URL + // for the client, and the relative URLs inside srcset are not automatically resolved to absolute URLs + // by browsers (in contrast to img.src). This means both SSR and DOM code could contain relative or absolute URLs. + (src_url_equal(element_urls[i][0], url) || src_url_equal(url, element_urls[i][0])) + ) ); } diff --git a/packages/svelte/test/utils/utils.test.js b/packages/svelte/test/utils/utils.test.js index cbdba7db32..31aab3320f 100644 --- a/packages/svelte/test/utils/utils.test.js +++ b/packages/svelte/test/utils/utils.test.js @@ -1,4 +1,4 @@ -import { assert, describe, it } from 'vitest'; +import { afterAll, assert, beforeAll, describe, it } from 'vitest'; import '../../src/compiler/compile/nodes/Slot.js'; // this needs to come first to force ESM to load things in a specific order to prevent circular dependency errors import { CONTENTEDITABLE_BINDINGS, @@ -9,7 +9,7 @@ import { } from '../../src/compiler/compile/utils/contenteditable.js'; import get_name_from_filename from '../../src/compiler/compile/utils/get_name_from_filename.js'; import { trim_end, trim_start } from '../../src/compiler/utils/trim.js'; -import { split_css_unit } from '../../src/runtime/internal/utils.js'; +import { split_css_unit, srcset_url_equal } from '../../src/runtime/internal/utils.js'; describe('utils', () => { describe('trim', () => { @@ -116,4 +116,51 @@ describe('utils', () => { }); }); }); + + describe('srcset_url_equal', () => { + function create_element(srcset) { + return /** @type {HTMLImageElement} */ ({ + srcset + }); + } + + beforeAll(() => { + let host = 'https://svelte.dev'; + let _href = ''; + // @ts-ignore + global.document = { + createElement: () => + /** @type {any} */ ({ + get href() { + return _href; + }, + set href(value) { + _href = host + value; + } + }) + }; + }); + + afterAll(() => { + // @ts-ignore + delete global.document; + }); + + it('should return true if urls are equal', () => { + assert.ok(srcset_url_equal(create_element('a'), 'a')); + assert.ok(srcset_url_equal(create_element('a 1x'), 'a 1x')); + assert.ok(srcset_url_equal(create_element('a 1x, b 2x'), 'a 1x, b 2x')); + assert.ok(srcset_url_equal(create_element('a 1x, b 2x'), 'a 1x, b 2x')); + }); + + it('should return true if urls are equal (abs/rel URLs)', () => { + assert.ok(srcset_url_equal(create_element('https://svelte.dev/a'), '/a')); + assert.ok(srcset_url_equal(create_element('/a'), 'https://svelte.dev/a')); + }); + + it('should return false if urls are different', () => { + assert.notOk(srcset_url_equal(create_element('a 1x'), 'b 1x')); + assert.notOk(srcset_url_equal(create_element('a 2x'), 'a 1x')); + }); + }); });