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 b905b4b5d44f..8f3cb5e57ec0 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -2001,16 +2001,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); } /** @@ -2027,15 +2028,16 @@ function push_invalidated(resource) { /** * Causes all `load` 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 1c4db540aef4..ae516aa46f3b 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -1444,6 +1444,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/utils.d.ts b/packages/kit/test/utils.d.ts index de03974f5baa..109b80021baa 100644 --- a/packages/kit/test/utils.d.ts +++ b/packages/kit/test/utils.d.ts @@ -16,7 +16,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 e7c84a51069c..da2d972bc952 100644 --- a/packages/kit/test/utils.js +++ b/packages/kit/test/utils.js @@ -12,7 +12,9 @@ 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) => invalidate(url, opts), url), + + invalidateAll: (opts) => page.evaluate(() => invalidateAll(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 5458c54e9715..4540e7846c59 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -2473,11 +2473,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` 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.