diff --git a/.changeset/old-rockets-film.md b/.changeset/old-rockets-film.md new file mode 100644 index 000000000000..7f6d7e4f9a95 --- /dev/null +++ b/.changeset/old-rockets-film.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: reset invalid resources after a successful invalidation diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index ed893add71b3..4427a1f9f3bf 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -82,6 +82,7 @@ export function create_client(app, target) { default_error_loader(); const container = __SVELTEKIT_EMBEDDED__ ? target : document.documentElement; + /** @type {Array<((url: URL) => boolean)>} */ const invalidated = []; @@ -165,13 +166,13 @@ export function create_client(app, target) { // Accept all invalidations as they come, don't swallow any while another invalidation // is running because subsequent invalidations may make earlier ones outdated, // but batch multiple synchronous invalidations. - pending_invalidate = pending_invalidate || Promise.resolve(); - await pending_invalidate; + await (pending_invalidate ||= Promise.resolve()); if (!pending_invalidate) return; pending_invalidate = null; const url = new URL(location.href); const intent = get_navigation_intent(url, true); + // Clear preload, it might be affected by the invalidation. // Also solves an edge case where a preload is triggered, the navigation for it // was then triggered and is still running while the invalidation kicks in, @@ -184,7 +185,7 @@ export function create_client(app, target) { if (navigation_result) { if (navigation_result.type === 'redirect') { - return goto(new URL(navigation_result.location, url).href, {}, 1, nav_token); + await goto(new URL(navigation_result.location, url).href, {}, 1, nav_token); } else { if (navigation_result.props.page !== undefined) { page = navigation_result.props.page; @@ -192,6 +193,8 @@ export function create_client(app, target) { root.$set(navigation_result.props); } } + + invalidated.length = 0; } /** @param {number} index */ diff --git a/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.svelte index e402d30d518c..b92e5839767e 100644 --- a/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/invalidation/depends/+page.svelte @@ -22,3 +22,12 @@ > invalidate server + +
neither
+ diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index 1c894af2e1c2..b140ca45ddc6 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -504,6 +504,11 @@ test.describe('Invalidation', () => { const next_shared = await page.textContent('p.shared'); expect(server).not.toBe(next_server); expect(shared).not.toBe(next_shared); + + await page.click('button.neither'); + await page.evaluate(() => window.promise); + expect(await page.textContent('p.server')).toBe(next_server); + expect(await page.textContent('p.shared')).toBe(next_shared); }); test('fetch in server load cannot be invalidated', async ({ page, app, request }) => { @@ -531,6 +536,11 @@ test.describe('Invalidation', () => { const next_shared = await page.textContent('p.shared'); expect(server).toBe(next_server); expect(shared).not.toBe(next_shared); + + await page.click('button.neither'); + await page.evaluate(() => window.promise); + expect(await page.textContent('p.server')).toBe(next_server); + expect(await page.textContent('p.shared')).toBe(next_shared); }); test('Parameter use is tracked even for routes that do not use the parameters', async ({