Skip to content
5 changes: 5 additions & 0 deletions .changeset/wild-mugs-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@sveltejs/kit": patch
---

fix: preserve state when invalidating
10 changes: 6 additions & 4 deletions packages/kit/src/runtime/client/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -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<void>}
*/
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);
}

/**
Expand All @@ -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<void>}
*/
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);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/kit/test/ambient.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ declare global {
}
) => Promise<void>;

const invalidate: (url: string) => Promise<void>;
const invalidate: (url: string, opts?: { resetPageState?: boolean }) => Promise<void>;
const invalidateAll: (opts?: { resetPageState?: boolean }) => Promise<void>;
const preloadData: (url: string) => Promise<void>;
const beforeNavigate: (fn: (navigation: BeforeNavigate) => void | boolean) => void;
const afterNavigate: (fn: (navigation: AfterNavigate) => void) => void;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<pre>{JSON.stringify(form)}</pre>
<button class="increment-success" on:click={() => update('success')}>Increment (success)</button>
<button class="increment-invalid" on:click={() => update('failure')}>Increment (invalid)</button>
<button class="invalidateAll" on:click={invalidateAll}>Invalidate</button>
<button class="invalidateAll" on:click={() => invalidateAll()}>Invalidate</button>
<button class="redirect" on:click={redirect}>Redirect</button>
<button class="error" on:click={error}>Error</button>
<a href="/actions/enhance">To enhance</a>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

<button data-id="one" on:click={one}>push state on current page</button>
<button data-id="two" on:click={two}>push state on child page</button>
<button data-id="invalidate" on:click={invalidateAll}>invalidate all</button>
<button data-id="invalidate" on:click={() => invalidateAll()}>invalidate all</button>

<p>active: {page.state.active ?? false}</p>
<span>{data.now}</span>
7 changes: 7 additions & 0 deletions packages/kit/test/apps/basics/test/client.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"]');
Expand Down
2 changes: 2 additions & 0 deletions packages/kit/test/setup.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
goto,
invalidate,
invalidateAll,
preloadCode,
preloadData,
beforeNavigate,
Expand All @@ -14,6 +15,7 @@ export function setup() {
Object.assign(window, {
goto,
invalidate,
invalidateAll,
preloadCode,
preloadData,
beforeNavigate,
Expand Down
3 changes: 2 additions & 1 deletion packages/kit/test/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export const test: TestType<
PlaywrightTestOptions & {
app: {
goto(url: string, opts?: { replaceState?: boolean }): Promise<void>;
invalidate(url: string): Promise<void>;
invalidate(url: string, opts?: { resetPageState?: boolean }): Promise<void>;
invalidateAll(opts?: { resetPageState?: boolean }): Promise<void>;
beforeNavigate(fn: (navigation: BeforeNavigate) => void | boolean): void;
afterNavigate(fn: (navigation: AfterNavigate) => void): void;
preloadCode(pathname: string): Promise<void>;
Expand Down
4 changes: 3 additions & 1 deletion packages/kit/test/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),

Expand Down
8 changes: 6 additions & 2 deletions packages/kit/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2473,11 +2473,15 @@ declare module '$app/navigation' {
* ```
* @param resource The invalidated URL
* */
export function invalidate(resource: string | URL | ((url: URL) => boolean)): Promise<void>;
export function invalidate(resource: string | URL | ((url: URL) => boolean), { resetPageState }?: {
resetPageState?: boolean;
}): Promise<void>;
/**
* 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<void>;
export function invalidateAll({ resetPageState }?: {
resetPageState?: boolean;
}): Promise<void>;
/**
* 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.
Expand Down
Loading