diff --git a/.changeset/eager-rats-turn.md b/.changeset/eager-rats-turn.md new file mode 100644 index 000000000000..74828a901213 --- /dev/null +++ b/.changeset/eager-rats-turn.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: Stop re-loading already-loaded CSS during server-side route resolution diff --git a/packages/kit/src/runtime/client/utils.js b/packages/kit/src/runtime/client/utils.js index 5c77c80d22f0..4a62702b9389 100644 --- a/packages/kit/src/runtime/client/utils.js +++ b/packages/kit/src/runtime/client/utils.js @@ -323,8 +323,8 @@ export function is_external_url(url, base, hash_routing) { return false; } -/** @type {Record} */ -const seen = {}; +/** @type {Set | null} */ +let seen = null; /** * Used for server-side resolution, to replicate Vite's CSS loading behaviour in production. @@ -341,13 +341,17 @@ export function load_css(deps) { ); const csp_nonce = csp_nonce_meta?.nonce || csp_nonce_meta?.getAttribute('nonce'); + seen ??= new Set( + Array.from(document.querySelectorAll('link[rel="stylesheet"]')).map((link) => { + return /** @type {HTMLLinkElement} */ (link).href; + }) + ); + for (const dep of deps) { - if (dep in seen) continue; - seen[dep] = true; + const href = new URL(dep, document.baseURI).href; - if (document.querySelector(`link[href="${dep}"][rel="stylesheet"]`)) { - continue; - } + if (seen.has(href)) continue; + seen.add(href); const link = document.createElement('link'); link.rel = 'stylesheet'; diff --git a/packages/kit/test/apps/basics/test/cross-platform/client.test.js b/packages/kit/test/apps/basics/test/cross-platform/client.test.js index 0a04a1c05b63..36b84c22eeb6 100644 --- a/packages/kit/test/apps/basics/test/cross-platform/client.test.js +++ b/packages/kit/test/apps/basics/test/cross-platform/client.test.js @@ -927,9 +927,9 @@ test.describe('Routing', () => { // we start watching requests await page.goto('/routing/form-get', { waitUntil: 'load' }); - expect(await page.textContent('h1')).toBe('...'); - expect(await page.textContent('h2')).toBe('enter'); - expect(await page.textContent('h3')).toBe('...'); + await expect(page.locator('h1')).toHaveText('...'); + await expect(page.locator('h2')).toHaveText('enter'); + await expect(page.locator('h3')).toHaveText('...'); /** @type {string[]} */ const requests = []; @@ -939,10 +939,10 @@ test.describe('Routing', () => { await page.locator('button').click(); // Filter out server-side route resolution request + await expect(page.locator('h1')).toHaveText('updated'); + await expect(page.locator('h2')).toHaveText('form'); + await expect(page.locator('h3')).toHaveText('bar'); expect(requests.filter((r) => !r.includes('__route.js'))).toEqual([]); - expect(await page.textContent('h1')).toBe('updated'); - expect(await page.textContent('h2')).toBe('form'); - expect(await page.textContent('h3')).toBe('bar'); }); test('responds to
submission with new tab', async ({ page }) => {