diff --git a/.changeset/wild-mugs-check.md b/.changeset/wild-mugs-check.md new file mode 100644 index 000000000000..b5b41cb7cda1 --- /dev/null +++ b/.changeset/wild-mugs-check.md @@ -0,0 +1,5 @@ +--- +"@sveltejs/kit": patch +--- + +fix: preserve state when invalidating diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 19cb46d6d7f2..6d621ae96f82 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -2370,16 +2370,17 @@ export function goto(url, opts = {}) { * invalidate((url) => url.pathname === '/path'); * ``` * @param {string | URL | ((url: URL) => boolean)} resource The invalidated URL + * @param {{ resetPageState?: boolean }} [options] * @returns {Promise} */ -export function invalidate(resource) { +export function invalidate(resource, { resetPageState = false } = {}) { if (!BROWSER) { throw new Error('Cannot call invalidate(...) on the server'); } push_invalidated(resource); - return _invalidate(); + return _invalidate(true, resetPageState); } /** @@ -2396,15 +2397,16 @@ function push_invalidated(resource) { /** * Causes all `load` and `query` functions belonging to the currently active page to re-run. Returns a `Promise` that resolves when the page is subsequently updated. + * @param {{ resetPageState?: boolean }} [options] * @returns {Promise} */ -export function invalidateAll() { +export function invalidateAll({ resetPageState = false } = {}) { if (!BROWSER) { throw new Error('Cannot call invalidateAll() on the server'); } force_invalidation = true; - return _invalidate(); + return _invalidate(true, resetPageState); } /** diff --git a/packages/kit/test/ambient.d.ts b/packages/kit/test/ambient.d.ts index 6db31b75d90f..906553e9a49c 100644 --- a/packages/kit/test/ambient.d.ts +++ b/packages/kit/test/ambient.d.ts @@ -14,7 +14,8 @@ declare global { } ) => Promise; - const invalidate: (url: string) => Promise; + const invalidate: (url: string, opts?: { resetPageState?: boolean }) => Promise; + const invalidateAll: (opts?: { resetPageState?: boolean }) => Promise; const preloadData: (url: string) => Promise; const beforeNavigate: (fn: (navigation: BeforeNavigate) => void | boolean) => void; const afterNavigate: (fn: (navigation: AfterNavigate) => void) => void; diff --git a/packages/kit/test/apps/basics/src/routes/actions/update-form/+page.svelte b/packages/kit/test/apps/basics/src/routes/actions/update-form/+page.svelte index fd69b8b08794..608fa9bc9332 100644 --- a/packages/kit/test/apps/basics/src/routes/actions/update-form/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/actions/update-form/+page.svelte @@ -20,7 +20,7 @@
{JSON.stringify(form)}
- + To enhance diff --git a/packages/kit/test/apps/basics/src/routes/shallow-routing/push-state/+page.svelte b/packages/kit/test/apps/basics/src/routes/shallow-routing/push-state/+page.svelte index 528e15c59e04..72d9ad41919b 100644 --- a/packages/kit/test/apps/basics/src/routes/shallow-routing/push-state/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/shallow-routing/push-state/+page.svelte @@ -17,7 +17,7 @@ - +

active: {page.state.active ?? false}

{data.now} diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index 8b5d6df581ee..0b89e3cc3dd4 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1740,6 +1740,13 @@ test.describe('Shallow routing', () => { await expect(page.locator('p')).toHaveText('active: true'); }); + test('Preserve state when invalidating', async ({ page, app }) => { + await page.goto('/shallow-routing/push-state'); + await page.locator('[data-id="one"]').click(); + await app.invalidateAll(); + await expect(page.locator('p')).toHaveText('active: true'); + }); + test('Replaces state on the current URL', async ({ baseURL, page, clicknav }) => { await page.goto('/shallow-routing/replace-state/b'); await clicknav('[href="/shallow-routing/replace-state"]'); diff --git a/packages/kit/test/setup.js b/packages/kit/test/setup.js index d6d34f54a815..87743436438e 100644 --- a/packages/kit/test/setup.js +++ b/packages/kit/test/setup.js @@ -1,6 +1,7 @@ import { goto, invalidate, + invalidateAll, preloadCode, preloadData, beforeNavigate, @@ -14,6 +15,7 @@ export function setup() { Object.assign(window, { goto, invalidate, + invalidateAll, preloadCode, preloadData, beforeNavigate, diff --git a/packages/kit/test/types.d.ts b/packages/kit/test/types.d.ts index 57cb80126fa7..58ca16d1348e 100644 --- a/packages/kit/test/types.d.ts +++ b/packages/kit/test/types.d.ts @@ -15,7 +15,8 @@ export const test: TestType< PlaywrightTestOptions & { app: { goto(url: string, opts?: { replaceState?: boolean }): Promise; - invalidate(url: string): Promise; + invalidate(url: string, opts?: { resetPageState?: boolean }): Promise; + invalidateAll(opts?: { resetPageState?: boolean }): Promise; beforeNavigate(fn: (navigation: BeforeNavigate) => void | boolean): void; afterNavigate(fn: (navigation: AfterNavigate) => void): void; preloadCode(pathname: string): Promise; diff --git a/packages/kit/test/utils.js b/packages/kit/test/utils.js index c41412520f35..4579cd4103f3 100644 --- a/packages/kit/test/utils.js +++ b/packages/kit/test/utils.js @@ -18,7 +18,10 @@ export const test = base.extend({ void use({ goto: (url, opts) => page.evaluate(({ url, opts }) => goto(url, opts), { url, opts }), - invalidate: (url) => page.evaluate((url) => invalidate(url), url), + invalidate: (url, opts) => + page.evaluate(({ url, opts }) => invalidate(url, opts), { url, opts }), + + invalidateAll: (opts) => page.evaluate((opts) => invalidateAll(opts), opts), beforeNavigate: (fn) => page.evaluate((fn) => beforeNavigate(fn), fn), diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 628973b7feee..4da3b8722258 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -3248,11 +3248,15 @@ declare module '$app/navigation' { * ``` * @param resource The invalidated URL * */ - export function invalidate(resource: string | URL | ((url: URL) => boolean)): Promise; + export function invalidate(resource: string | URL | ((url: URL) => boolean), { resetPageState }?: { + resetPageState?: boolean; + }): Promise; /** * Causes all `load` and `query` functions belonging to the currently active page to re-run. Returns a `Promise` that resolves when the page is subsequently updated. * */ - export function invalidateAll(): Promise; + export function invalidateAll({ resetPageState }?: { + resetPageState?: boolean; + }): Promise; /** * Causes all currently active remote functions to refresh, and all `load` functions belonging to the currently active page to re-run (unless disabled via the option argument). * Returns a `Promise` that resolves when the page is subsequently updated.