From c225b0763f991334b49a1eae342ef832f867b49d Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Thu, 9 Jul 2026 13:43:13 +0200 Subject: [PATCH 1/8] breaking: add `refresh`/`refreshAll` and deprecate `invalidate`/`invalidateAll` - Added a `refresh` method that works like `invalidate` but does not reset `page.state` - Added new `refresh` method (which also doesn't reset `page.state`) - Deprecated `invalidate(All)` in favor of `refresh(All)` (also on `goto`) - Removed the `includeLoadFunctions` option from `refreshAll` - it now always reruns `load` functions Closes #11783 Closes #13139 --- .changeset/refresh-page-state.md | 5 + .../docs/20-core-concepts/20-load.md | 22 ++-- .../docs/20-core-concepts/30-form-actions.md | 6 +- packages/kit/src/exports/public.d.ts | 16 +-- packages/kit/src/runtime/app/forms.js | 4 +- packages/kit/src/runtime/app/navigation.js | 1 + packages/kit/src/runtime/client/client.js | 123 +++++++++++------- .../client/remote-functions/form.svelte.js | 12 +- packages/kit/test/ambient.d.ts | 1 + .../apps/async/src/routes/remote/+page.svelte | 3 - .../async/src/routes/remote/live/+page.svelte | 18 +-- .../kit/test/apps/async/test/client.test.js | 30 ++--- .../routes/actions/update-form/+page.svelte | 4 +- .../load/cache-control/bust/+page.svelte | 4 +- .../load/cache-control/default/+page.svelte | 4 +- .../load/cache-control/force/+page.svelte | 4 +- .../change-detection/one/[x]/+page.svelte | 10 +- .../load/invalidation/depends/+page.svelte | 14 +- .../during-navigation/[slug]/+layout.svelte | 14 +- .../invalidation/forced-goto/+page.svelte | 8 +- .../load/invalidation/forced/+page.svelte | 8 +- .../invalidate-then-goto/+page.svelte | 8 +- .../multiple-batched/+page.svelte | 8 +- .../load/invalidation/multiple/+layout.svelte | 12 +- .../multiple/redirect/+page.svelte | 4 +- .../routes/reroute/invalidate/+page.svelte | 4 +- .../shallow-routing/push-state/+page.svelte | 4 +- .../routes/shallow-routing/refresh/+page.js | 7 + .../shallow-routing/refresh/+page.svelte | 25 ++++ .../kit/test/apps/basics/test/client.test.js | 100 +++++++++++--- packages/kit/test/apps/basics/test/test.js | 4 +- packages/kit/test/setup.js | 2 + packages/kit/test/types.d.ts | 1 + packages/kit/test/utils.js | 2 + packages/kit/types/index.d.ts | 48 +++++-- 35 files changed, 344 insertions(+), 196 deletions(-) create mode 100644 .changeset/refresh-page-state.md create mode 100644 packages/kit/test/apps/basics/src/routes/shallow-routing/refresh/+page.js create mode 100644 packages/kit/test/apps/basics/src/routes/shallow-routing/refresh/+page.svelte diff --git a/.changeset/refresh-page-state.md b/.changeset/refresh-page-state.md new file mode 100644 index 000000000000..d228238ee0e2 --- /dev/null +++ b/.changeset/refresh-page-state.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': major +--- + +breaking: add `refresh`/`refreshAll` and deprecate `invalidate`/`invalidateAll` diff --git a/documentation/docs/20-core-concepts/20-load.md b/documentation/docs/20-core-concepts/20-load.md index 2c895dc6af72..a5da64d32c09 100644 --- a/documentation/docs/20-core-concepts/20-load.md +++ b/documentation/docs/20-core-concepts/20-load.md @@ -638,7 +638,9 @@ export async function load({ untrack, url }) { ### Manual invalidation -You can also rerun `load` functions that apply to the current page using [`invalidate(url)`]($app-navigation#invalidate), which reruns all `load` functions that depend on `url`, and [`invalidateAll()`]($app-navigation#invalidateAll), which reruns every `load` function. Server load functions will never automatically depend on a fetched `url` to avoid leaking secrets to the client. +You can also rerun `load` functions that apply to the current page using [`refresh(url)`]($app-navigation#refresh), which reruns all `load` functions that depend on `url`, and [`refreshAll()`]($app-navigation#refreshAll), which reruns every `load` function and all active queries. Server load functions will never automatically depend on a fetched `url` to avoid leaking secrets to the client. + +> [!NOTE] `refresh` and `refreshAll` do _not_ reset `page.state`. This is useful when you're using [shallow routing](shallow-routing) and want to refresh data without losing the current page state. The deprecated `invalidate` and `invalidateAll` functions _do_ reset `page.state` — prefer `refresh` and `refreshAll`. A `load` function depends on `url` if it calls `fetch(url)` or `depends(url)`. Note that `url` can be a custom identifier that starts with `[a-z]:`: @@ -646,10 +648,10 @@ A `load` function depends on `url` if it calls `fetch(url)` or `depends(url)`. N /// file: src/routes/random-number/+page.js /** @type {import('./$types').PageLoad} */ export async function load({ fetch, depends }) { - // load reruns when `invalidate('https://api.example.com/random-number')` is called... + // load reruns when `refresh('https://api.example.com/random-number')` is called... const response = await fetch('https://api.example.com/random-number'); - // ...or when `invalidate('app:random')` is called + // ...or when `refresh('app:random')` is called depends('app:random'); return { @@ -661,17 +663,17 @@ export async function load({ fetch, depends }) { ```svelte @@ -688,8 +690,8 @@ To summarize, a `load` function will rerun in the following situations: - It calls `url.searchParams.get(...)`, `url.searchParams.getAll(...)` or `url.searchParams.has(...)` and the parameter in question changes. Accessing other properties of `url.searchParams` will have the same effect as accessing `url.search`. - It calls `await parent()` and a parent `load` function reran - A child `load` function calls `await parent()` and is rerunning, and the parent is a server load function -- It declared a dependency on a specific URL via [`fetch`](#Making-fetch-requests) (universal load only) or [`depends`](@sveltejs-kit#LoadEvent), and that URL was marked invalid with [`invalidate(url)`]($app-navigation#invalidate) -- All active `load` functions were forcibly rerun with [`invalidateAll()`]($app-navigation#invalidateAll) +- It declared a dependency on a specific URL via [`fetch`](#Making-fetch-requests) (universal load only) or [`depends`](@sveltejs-kit#LoadEvent), and that URL was marked invalid with [`refresh(url)`]($app-navigation#refresh) +- All active `load` functions were forcibly rerun with [`refreshAll()`]($app-navigation#refreshAll) `params` and `url` can change in response to a `` link click, a [`
` interaction](form-actions#GET-vs-POST), a [`goto`]($app-navigation#goto) invocation, or a [`redirect`](@sveltejs-kit#redirect). diff --git a/documentation/docs/20-core-concepts/30-form-actions.md b/documentation/docs/20-core-concepts/30-form-actions.md index c8e69846efa5..6642f17ba4ad 100644 --- a/documentation/docs/20-core-concepts/30-form-actions.md +++ b/documentation/docs/20-core-concepts/30-form-actions.md @@ -433,7 +433,7 @@ We can also implement progressive enhancement ourselves, without `use:enhance`, ```svelte * @@ -1812,7 +1812,7 @@ export interface ServerLoadEvent< */ parent: () => Promise; /** - * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. + * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`refresh()`](https://svelte.dev/docs/kit/$app-navigation#refresh) to cause `load` to rerun. * * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. * @@ -1820,7 +1820,7 @@ export interface ServerLoadEvent< * * Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the [URI specification](https://www.rfc-editor.org/rfc/rfc3986.html). * - * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`d after a button click, making the `load` function rerun. + * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `refresh`ed after a button click, making the `load` function rerun. * * ```js * /// file: src/routes/+page.js @@ -1835,12 +1835,12 @@ export interface ServerLoadEvent< * ```html * /// file: src/routes/+page.svelte * * diff --git a/packages/kit/src/runtime/app/forms.js b/packages/kit/src/runtime/app/forms.js index 4d9b5238d7a2..adb55c8247a3 100644 --- a/packages/kit/src/runtime/app/forms.js +++ b/packages/kit/src/runtime/app/forms.js @@ -1,7 +1,7 @@ import * as devalue from 'devalue'; import { BROWSER, DEV } from 'esm-env'; import { noop } from '../../utils/functions.js'; -import { invalidateAll } from './navigation.js'; +import { refreshAll } from './navigation.js'; import { app as client_app, applyAction, handle_error } from '../client/client.js'; import { app as server_app } from '../server/app.js'; @@ -106,7 +106,7 @@ export function enhance(form_element, submit = noop) { HTMLFormElement.prototype.reset.call(form_element); } if (shouldInvalidateAll) { - await invalidateAll(); + await refreshAll(); } } diff --git a/packages/kit/src/runtime/app/navigation.js b/packages/kit/src/runtime/app/navigation.js index dd210cdb5fd3..f191ca51aca5 100644 --- a/packages/kit/src/runtime/app/navigation.js +++ b/packages/kit/src/runtime/app/navigation.js @@ -5,6 +5,7 @@ export { goto, invalidate, invalidateAll, + refresh, refreshAll, onNavigate, preloadCode, diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 3cb7b4a53f45..8f7361f17d66 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -403,7 +403,7 @@ export async function start(_app, _target, hydrate) { _start_router(); } -async function _invalidate(include_load_functions = true, reset_page_state = true) { +async function _invalidate(reset_page_state = true) { // 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. @@ -442,39 +442,35 @@ async function _invalidate(include_load_functions = true, reset_page_state = tru } } - if (include_load_functions) { - const prev_state = page.state; - const navigation_result = intent && (await load_route(intent)); - if (!navigation_result || token !== invalidation_token || nav_token !== navigation_token) { - return; - } + const prev_state = page.state; + const navigation_result = intent && (await load_route(intent)); + if (!navigation_result || token !== invalidation_token || nav_token !== navigation_token) { + return; + } - if (navigation_result.type === 'redirect') { - return _goto( - new URL(navigation_result.location, current.url).href, - { replaceState: true }, - 1, - token - ); - } + if (navigation_result.type === 'redirect') { + return _goto( + new URL(navigation_result.location, current.url).href, + { replaceState: true }, + 1, + token + ); + } - // A navigation started before the invalidation and ended before it finished. The invalidation did not redirect, - // hence it likely contains outdated data now, so we ignore it. - if (navigating && !is_navigating) { - return; - } + // A navigation started before the invalidation and ended before it finished. The invalidation did not redirect, + // hence it likely contains outdated data now, so we ignore it. + if (navigating && !is_navigating) { + return; + } - // This is a bit hacky but allows us not having to pass that boolean around, making things harder to reason about - if (!reset_page_state) { - navigation_result.props.page.state = prev_state; - } - update(navigation_result.props.page); - current = { ...navigation_result.state, nav: current.nav }; - reset_invalidation(); - root.$set(navigation_result.props); - } else { - reset_invalidation(); + // Preserve `page.state` when invalidating without resetting it (e.g. `refresh`/`refreshAll`) + if (!reset_page_state) { + navigation_result.props.page.state = prev_state; } + update(navigation_result.props.page); + current = { ...navigation_result.state, nav: current.nav }; + reset_invalidation(); + root.$set(navigation_result.props); // only wait for promises that are connected to queries that still exist /** @type {Promise[]} */ @@ -527,7 +523,7 @@ function persist_state() { /** * @param {string | URL} url - * @param {{ replaceState?: boolean; noScroll?: boolean; keepFocus?: boolean; invalidateAll?: boolean; invalidate?: Array boolean)>; state?: Record }} options + * @param {{ replaceState?: boolean; noScroll?: boolean; keepFocus?: boolean; refreshAll?: boolean; refresh?: Array boolean)>; state?: Record }} options * @param {number} redirect_count * @param {{}} [nav_token] * @param {NavigationIntent | undefined} [intent] navigation intent, when already known by the caller (avoids recomputing it) @@ -539,9 +535,9 @@ export async function _goto(url, options, redirect_count, nav_token, intent) { /** @type {Set} */ let live_query_keys; - // Clear preload cache when invalidateAll is true to ensure fresh data + // Clear preload cache when refreshAll is true to ensure fresh data // after form submissions or explicit invalidations - if (options.invalidateAll) { + if (options.refreshAll) { discard_load_cache(); } @@ -556,7 +552,7 @@ export async function _goto(url, options, redirect_count, nav_token, intent) { nav_token, intent, accept: () => { - if (options.invalidateAll) { + if (options.refreshAll) { force_invalidation = true; query_keys = new Set(); for (const [id, entries] of query_map) { @@ -576,13 +572,13 @@ export async function _goto(url, options, redirect_count, nav_token, intent) { } } - if (options.invalidate) { - options.invalidate.forEach(push_invalidated); + if (options.refresh) { + options.refresh.forEach(push_invalidated); } } }); - if (options.invalidateAll) { + if (options.refreshAll) { // TODO the ticks shouldn't be necessary, something inside Svelte itself is buggy // when a query in a layout that still exists after page change is refreshed earlier than this void svelte @@ -2310,8 +2306,10 @@ export function disableScrollHandling() { * @param {boolean} [opts.replaceState] If `true`, will replace the current `history` entry rather than creating a new one with `pushState` * @param {boolean} [opts.noScroll] If `true`, the browser will maintain its scroll position rather than scrolling to the top of the page after navigation * @param {boolean} [opts.keepFocus] If `true`, the currently focused element will retain focus after navigation. Otherwise, focus will be reset to the body - * @param {boolean} [opts.invalidateAll] If `true`, all `load` functions of the page will be rerun. See https://svelte.dev/docs/kit/load#rerunning-load-functions for more info on invalidation. - * @param {Array boolean)>} [opts.invalidate] Causes any load functions to re-run if they depend on one of the urls + * @param {boolean} [opts.refreshAll] If `true`, all `load` functions and queries of the page will be rerun. See https://svelte.dev/docs/kit/load#rerunning-load-functions for more info on invalidation. + * @param {Array boolean)>} [opts.refresh] Causes any load functions to re-run if they depend on one of the urls + * @param {boolean} [opts.invalidateAll] Deprecated in favor of opts.refreshAll. + * @param {Array boolean)>} [opts.invalidate] Deprecated in favor of opts.refresh. * @param {App.PageState} [opts.state] An optional object that will be available as `page.state` * @returns {Promise} */ @@ -2340,6 +2338,8 @@ export async function goto(url, opts = {}) { ); } + opts.refresh = opts.refresh ?? opts.invalidate; + opts.refreshAll = opts.refreshAll ?? opts.invalidateAll; return _goto(url, opts, 0, {}, intent); } @@ -2358,6 +2358,10 @@ export async function goto(url, opts = {}) { * * invalidate((url) => url.pathname === '/path'); * ``` + * + * Note that this resets `page.state` to an empty object. If you want to preserve `page.state` (for example when using [shallow routing](https://svelte.dev/docs/kit/shallow-routing)), use `refresh` instead. + * + * @deprecated Use [`refresh`](https://svelte.dev/docs/kit/$app-navigation#refresh) instead. Unlike `invalidate`, `refresh` does not reset `page.state`. * @param {string | URL | ((url: URL) => boolean)} resource The invalidated URL * @returns {Promise} */ @@ -2371,6 +2375,34 @@ export function invalidate(resource) { return _invalidate(); } +/** + * Causes any `load` functions belonging to the currently active page to re-run if they depend on the `url` in question, via `fetch` or `depends`. Returns a `Promise` that resolves when the page is subsequently updated. + * + * If the argument is given as a `string` or `URL`, it must resolve to the same URL that was passed to `fetch` or `depends` (including query parameters). + * To create a custom identifier, use a string beginning with `[a-z]+:` (e.g. `custom:state`) — this is a valid URL. + * + * The `function` argument can be used define a custom predicate. It receives the full `URL` and causes `load` to rerun if `true` is returned. + * This can be useful if you want to invalidate based on a pattern instead of a exact match. + * + * ```ts + * // Example: Match '/path' regardless of the query parameters + * import { refresh } from '$app/navigation'; + * + * refresh((url) => url.pathname === '/path'); + * ``` + * @param {string | URL | ((url: URL) => boolean)} resource The invalidated URL + * @returns {Promise} + */ +export function refresh(resource) { + if (!BROWSER) { + throw new Error('Cannot call refresh(...) on the server'); + } + + push_invalidated(resource); + + return _invalidate(false); +} + /** * @param {string | URL | ((url: URL) => boolean)} resource The invalidated URL */ @@ -2385,6 +2417,10 @@ 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. + * + * Note that this resets `page.state` to an empty object. If you want to preserve `page.state` (for example when using [shallow routing](https://svelte.dev/docs/kit/shallow-routing)), use `refreshAll` instead. + * + * @deprecated Use [`refreshAll`](https://svelte.dev/docs/kit/$app-navigation#refreshAll) instead. Unlike `invalidateAll`, `refreshAll` does not reset `page.state`. * @returns {Promise} */ export function invalidateAll() { @@ -2397,18 +2433,17 @@ export function invalidateAll() { } /** - * 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). + * Causes all currently active remote functions to refresh, and all `load` functions belonging to the currently active page to re-run. * Returns a `Promise` that resolves when the page is subsequently updated. - * @param {{ includeLoadFunctions?: boolean }} [options] * @returns {Promise} */ -export function refreshAll({ includeLoadFunctions = true } = {}) { +export function refreshAll() { if (!BROWSER) { throw new Error('Cannot call refreshAll() on the server'); } force_invalidation = true; - return _invalidate(includeLoadFunctions, false); + return _invalidate(false); } /** @@ -2599,7 +2634,7 @@ export async function applyAction(result) { if (result.type === 'error') { await set_nearest_error_page(result.error); } else if (result.type === 'redirect') { - await _goto(result.location, { invalidateAll: true }, 0); + await _goto(result.location, { refreshAll: true }, 0); } else { page.form = result.data; page.status = result.status; diff --git a/packages/kit/src/runtime/client/remote-functions/form.svelte.js b/packages/kit/src/runtime/client/remote-functions/form.svelte.js index 38089eaead61..a83a1e0d1b08 100644 --- a/packages/kit/src/runtime/client/remote-functions/form.svelte.js +++ b/packages/kit/src/runtime/client/remote-functions/form.svelte.js @@ -8,8 +8,8 @@ import { query_responses, _goto, set_nearest_error_page, - invalidateAll, - handle_error + handle_error, + refreshAll } from '../client.js'; import { tick } from 'svelte'; import { categorize_updates, remote_request } from './shared.svelte.js'; @@ -227,14 +227,14 @@ export function form(id) { // if the developer took control of updates via `.updates(...)` (even with // no arguments), or the server performed explicit refreshes, don't invalidateAll - const should_invalidate = refreshes === null && !response.r; + const should_refresh = refreshes === null && !response.r; if (response.redirect) { // Use internal version to allow redirects to external URLs void _goto( response.redirect, { - invalidateAll: should_invalidate + refreshAll: should_refresh }, 0 ); @@ -244,8 +244,8 @@ export function form(id) { const succeeded = raw_issues.length === 0; if (succeeded) { - if (should_invalidate) { - void invalidateAll(); + if (should_refresh) { + void refreshAll(); } } else { if (DEV) { diff --git a/packages/kit/test/ambient.d.ts b/packages/kit/test/ambient.d.ts index 6db31b75d90f..44333f6ec518 100644 --- a/packages/kit/test/ambient.d.ts +++ b/packages/kit/test/ambient.d.ts @@ -15,6 +15,7 @@ declare global { ) => Promise; const invalidate: (url: string) => Promise; + const refresh: (url: string) => 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/async/src/routes/remote/+page.svelte b/packages/kit/test/apps/async/src/routes/remote/+page.svelte index 62f18a5c4238..8860c5059dd9 100644 --- a/packages/kit/test/apps/async/src/routes/remote/+page.svelte +++ b/packages/kit/test/apps/async/src/routes/remote/+page.svelte @@ -172,9 +172,6 @@ - /remote/event diff --git a/packages/kit/test/apps/async/src/routes/remote/live/+page.svelte b/packages/kit/test/apps/async/src/routes/remote/live/+page.svelte index 4251d6a37d56..6c4798558ced 100644 --- a/packages/kit/test/apps/async/src/routes/remote/live/+page.svelte +++ b/packages/kit/test/apps/async/src/routes/remote/live/+page.svelte @@ -1,5 +1,5 @@ @@ -111,5 +111,5 @@

{stream_log}

- -

{invalidate_state}

+ +

{refresh_state}

diff --git a/packages/kit/test/apps/async/test/client.test.js b/packages/kit/test/apps/async/test/client.test.js index 208876495c8a..5b47b97a6e62 100644 --- a/packages/kit/test/apps/async/test/client.test.js +++ b/packages/kit/test/apps/async/test/client.test.js @@ -372,20 +372,6 @@ test.describe('remote function mutations', () => { expect(request_count).toBe(5); }); - test('refreshAll({ includeLoadFunctions: false }) reloads remote functions only', async ({ - page - }) => { - await page.goto('/remote'); - await expect(page.locator('#count-result')).toHaveText('0 / 0 (false)'); - - let request_count = 0; - page.on('request', (r) => (request_count += r.url().includes('/_app/remote') ? 1 : 0)); - - await page.click('#refresh-remote-only'); - await page.waitForTimeout(100); // allow things to rerun - expect(request_count).toBe(4); - }); - test('command tracks pending state', async ({ page }) => { await page.goto('/remote'); @@ -806,7 +792,7 @@ test.describe('remote function mutations', () => { await page.click('#reset'); }); - test('for await consumers continue receiving values across invalidateAll-triggered reconnects', async ({ + test('for await consumers continue receiving values across refreshAll-triggered reconnects', async ({ page }) => { await page.goto('/remote/live'); @@ -817,11 +803,11 @@ test.describe('remote function mutations', () => { // the first value should be the current value (0) await expect(page.locator('#stream-log')).toHaveText(/0/); - // invalidateAll() calls reconnect(), which keeps the existing fan-out + // refreshAll() calls reconnect(), which keeps the existing fan-out // open so active `for await` consumers continue receiving values from // the new connection without interruption. - await page.click('#run-invalidate-all'); - await expect(page.locator('#invalidate-state')).toHaveText('resolved'); + await page.click('#run-refresh-all'); + await expect(page.locator('#refresh-state')).toHaveText('resolved'); // Trigger a new value — the still-attached consumer must see it. // Before the fix the fan-out was replaced, orphaning the subscriber so @@ -832,7 +818,7 @@ test.describe('remote function mutations', () => { await page.click('#reset'); }); - test('invalidateAll resolves while a live query is offline', async ({ page, context }) => { + test('refreshAll resolves while a live query is offline', async ({ page, context }) => { await page.goto('/remote/live'); await page.click('#reset'); await expect(page.locator('#connected')).toHaveText('true'); @@ -840,9 +826,9 @@ test.describe('remote function mutations', () => { await context.setOffline(true); // reconnect()'s handshake must settle on every #main exit path (here: - // offline) so that awaiting invalidateAll() doesn't deadlock. - await page.click('#run-invalidate-all'); - await expect(page.locator('#invalidate-state')).toHaveText(/resolved|rejected/); + // offline) so that awaiting refreshAll() doesn't deadlock. + await page.click('#run-refresh-all'); + await expect(page.locator('#refresh-state')).toHaveText(/resolved|rejected/); await context.setOffline(false); }); 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 e42c285b54c8..3cee4d352d6f 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 @@ -1,6 +1,6 @@ diff --git a/packages/kit/test/apps/basics/src/routes/load/cache-control/default/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/cache-control/default/+page.svelte index f9ee117d09ac..aab9aee2a828 100644 --- a/packages/kit/test/apps/basics/src/routes/load/cache-control/default/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/cache-control/default/+page.svelte @@ -1,5 +1,5 @@ diff --git a/packages/kit/test/apps/basics/src/routes/load/cache-control/force/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/cache-control/force/+page.svelte index 5f243b2206b6..49599729d365 100644 --- a/packages/kit/test/apps/basics/src/routes/load/cache-control/force/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/cache-control/force/+page.svelte @@ -1,12 +1,12 @@ diff --git a/packages/kit/test/apps/basics/src/routes/load/change-detection/one/[x]/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/change-detection/one/[x]/+page.svelte index 108bab003f7f..e4b68e69d42e 100644 --- a/packages/kit/test/apps/basics/src/routes/load/change-detection/one/[x]/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/change-detection/one/[x]/+page.svelte @@ -1,5 +1,5 @@ @@ -8,17 +8,17 @@ b setTimeout(() => invalidateAll(), 50)} + data-testid="nav-b-refresh" + onclick={() => setTimeout(() => refreshAll(), 50)} > - b+invalidate + b+refresh setTimeout(() => invalidateAll(), 50)} + data-testid="nav-a-refresh" + onclick={() => setTimeout(() => refreshAll(), 50)} > - a+invalidate + a+refresh diff --git a/packages/kit/test/apps/basics/src/routes/load/invalidation/forced-goto/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/invalidation/forced-goto/+page.svelte index 76d828cac677..129a6078e95f 100644 --- a/packages/kit/test/apps/basics/src/routes/load/invalidation/forced-goto/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/invalidation/forced-goto/+page.svelte @@ -1,5 +1,5 @@ @@ -9,11 +9,11 @@ id="multiple-batched" onclick={(event) => { const btn = event.currentTarget; - invalidate('multiple:invalidations-go-brr'); - invalidate('multiple:invalidations-go-brr'); + refresh('multiple:invalidations-go-brr'); + refresh('multiple:invalidations-go-brr'); Promise.resolve() - .then(() => invalidate('multiple:invalidations-go-brr')) + .then(() => refresh('multiple:invalidations-go-brr')) .then(() => { btn.dataset.done = 'true'; }); diff --git a/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/+layout.svelte b/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/+layout.svelte index 0405e1d6b9ad..782fe9535895 100644 --- a/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/+layout.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/+layout.svelte @@ -1,5 +1,5 @@ - - - + + +

layout: {page.data.count_layout}, page: {page.data.count_page}

diff --git a/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/redirect/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/redirect/+page.svelte index 141db8bcff59..21d1cc0321d9 100644 --- a/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/redirect/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/redirect/+page.svelte @@ -1,10 +1,10 @@ diff --git a/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.svelte b/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.svelte index 77c4945350a1..16cb78956569 100644 --- a/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/reroute/invalidate/+page.svelte @@ -1,10 +1,10 @@ - + {#if data.request}

data request: {data.request}

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 318d0c91cbd9..07c88d358be5 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 @@ -1,5 +1,5 @@ + +

refresh

+ + + + + + + +

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 1e5b36b519f5..ff247d939e3a 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -59,24 +59,24 @@ test.describe('Load', () => { await app.goto('/load/change-detection/one/b'); expect(await page.textContent('h2')).toBe('x: b: 3'); - await app.invalidate('/load/change-detection/data.json'); + await app.refresh('/load/change-detection/data.json'); expect(await page.textContent('h1')).toBe('layout loads: 2'); expect(await page.textContent('h2')).toBe('x: b: 3'); - await app.invalidate('/load/change-detection/data.json'); + await app.refresh('/load/change-detection/data.json'); expect(await page.textContent('h1')).toBe('layout loads: 3'); expect(await page.textContent('h2')).toBe('x: b: 3'); - await app.invalidate('custom:change-detection-layout'); + await app.refresh('custom:change-detection-layout'); expect(await page.textContent('h1')).toBe('layout loads: 4'); expect(await page.textContent('h2')).toBe('x: b: 3'); - await page.click('button:has-text("invalidate change-detection/data.json")'); + await page.click('button:has-text("refresh change-detection/data.json")'); await page.waitForFunction('window.invalidated'); expect(await page.textContent('h1')).toBe('layout loads: 5'); expect(await page.textContent('h2')).toBe('x: b: 3'); - await page.click('button:has-text("invalidate all")'); + await page.click('button:has-text("refresh all")'); await page.waitForFunction('window.invalidated'); expect(await page.textContent('h1')).toBe('layout loads: 6'); expect(await page.textContent('h2')).toBe('x: b: 4'); @@ -536,13 +536,13 @@ test.describe('Invalidation', () => { await page.goto('/load/invalidation/forced'); expect(await page.textContent('h1')).toBe('a: 0, b: 0'); - await page.click('button.invalidateall'); + await page.click('button.refreshall'); await page.evaluate( () => /** @type {Window & typeof globalThis & { promise: Promise }} */ (window).promise ); expect(await page.textContent('h1')).toBe('a: 1, b: 1'); - await page.click('button.invalidateall'); + await page.click('button.refreshall'); await page.evaluate( () => /** @type {Window & typeof globalThis & { promise: Promise }} */ (window).promise ); @@ -590,7 +590,7 @@ test.describe('Invalidation', () => { await expect(btn).toHaveText('2'); }); - test('invalidateAll persists through redirects', async ({ page }) => { + test('refreshAll persists through redirects', async ({ page }) => { await page.goto('/load/invalidation/multiple/redirect'); await page.locator('button.redirect').click(); await expect(page.locator('p.redirect-state')).toHaveText('Redirect state: done'); @@ -628,7 +628,7 @@ test.describe('Invalidation', () => { const selector = '[data-testid="count"]'; expect(await page.textContent(selector)).toBe('1'); - await app.invalidate('/load/invalidation/server-fetch/count.json'); + await app.refresh('/load/invalidation/server-fetch/count.json'); expect(await page.textContent(selector)).toBe('1'); }); @@ -795,14 +795,14 @@ test.describe('Invalidation', () => { await expect(page.getByText('updated')).toBeVisible(); }); - test('goto after invalidation does not reset state', async ({ page }) => { + test('goto after refresh does not reset state', async ({ page }) => { await page.goto('/load/invalidation/invalidate-then-goto'); const layout = await page.textContent('p.layout'); const _page = await page.textContent('p.page'); expect(layout).toBeDefined(); expect(_page).toBeDefined(); - await page.click('button.invalidate'); + await page.click('button.refresh'); await page.evaluate( () => /** @type {Window & typeof globalThis & { promise: Promise }} */ (window).promise ); @@ -821,28 +821,28 @@ test.describe('Invalidation', () => { expect(next_page_2).not.toBe(next_page_1); }); - test('invalidateAll finishing after navigation does not apply stale data', async ({ + test('refreshAll finishing after navigation does not apply stale data', async ({ page, clicknav }) => { await page.goto('/load/invalidation/during-navigation/a'); await expect(page.locator('[data-testid="scores"]')).toHaveText('1 - 1'); - await clicknav('[data-testid="nav-b-invalidate"]'); + await clicknav('[data-testid="nav-b-refresh"]'); await expect(page.locator('[data-testid="scores"]')).toHaveText('2 - 2'); await page.waitForTimeout(400); await expect(page.locator('[data-testid="scores"]')).toHaveText('2 - 2'); }); - test('invalidateAll finishing before navigation ends does not prevent navigation', async ({ + test('refreshAll finishing before navigation ends does not prevent navigation', async ({ page, clicknav }) => { await page.goto('/load/invalidation/during-navigation/b'); await expect(page.locator('[data-testid="scores"]')).toHaveText('2 - 2'); - await clicknav('[data-testid="nav-a-invalidate"]'); + await clicknav('[data-testid="nav-a-refresh"]'); await expect(page.locator('[data-testid="scores"]')).toHaveText('1 - 1'); }); }); @@ -1558,8 +1558,8 @@ test.describe('goto', () => { const expectGoback = makeExpectGoback(testFinishPage, testEntryPage); - test('app.invalidate', async ({ app, page }) => { - await app.invalidate('app:goto'); + test('app.refresh', async ({ app, page }) => { + await app.refresh('app:goto'); await expectGoback(page); }); @@ -1667,7 +1667,7 @@ test.describe('Shallow routing', () => { await expect(page.locator('p')).toHaveText('active: true'); }); - test('Invalidates the correct route after pushing state to a new URL', async ({ + test('Refreshes the correct route after pushing state to a new URL', async ({ baseURL, page }) => { @@ -1679,7 +1679,7 @@ test.describe('Shallow routing', () => { await page.locator('[data-id="two"]').click(); expect(page.url()).toBe(`${baseURL}/shallow-routing/push-state/a`); - await page.locator('[data-id="invalidate"]').click(); + await page.locator('[data-id="refresh"]').click(); await expect(page.locator('h1')).toHaveText('parent'); await expect(page.locator('span')).not.toHaveText(now); }); @@ -1742,6 +1742,66 @@ test.describe('Shallow routing', () => { await page.locator('button').click(); await expect(page.locator('p')).toHaveText('count: 1'); }); + + test('refresh reruns load functions without resetting page.state', async ({ page }) => { + await page.goto('/shallow-routing/refresh'); + await expect(page.locator('p')).toHaveText('active: false'); + + const now = /** @type {string} */ (await page.locator('span').textContent()); + + await page.locator('[data-id="activate"]').click(); + await expect(page.locator('p')).toHaveText('active: true'); + + await page.locator('[data-id="refresh"]').click(); + await page.evaluate(() => window.promise); + await expect(page.locator('p')).toHaveText('active: true'); + await expect(page.locator('span')).not.toHaveText(now); + }); + + test('refreshAll reruns load functions without resetting page.state', async ({ page }) => { + await page.goto('/shallow-routing/refresh'); + await expect(page.locator('p')).toHaveText('active: false'); + + const now = /** @type {string} */ (await page.locator('span').textContent()); + + await page.locator('[data-id="activate"]').click(); + await expect(page.locator('p')).toHaveText('active: true'); + + await page.locator('[data-id="refreshAll"]').click(); + await page.evaluate(() => window.promise); + await expect(page.locator('p')).toHaveText('active: true'); + await expect(page.locator('span')).not.toHaveText(now); + }); + + test('invalidate resets page.state', async ({ page }) => { + await page.goto('/shallow-routing/refresh'); + await expect(page.locator('p')).toHaveText('active: false'); + + const now = /** @type {string} */ (await page.locator('span').textContent()); + + await page.locator('[data-id="activate"]').click(); + await expect(page.locator('p')).toHaveText('active: true'); + + await page.locator('[data-id="invalidate"]').click(); + await page.evaluate(() => window.promise); + await expect(page.locator('p')).toHaveText('active: false'); + await expect(page.locator('span')).not.toHaveText(now); + }); + + test('invalidateAll resets page.state', async ({ page }) => { + await page.goto('/shallow-routing/refresh'); + await expect(page.locator('p')).toHaveText('active: false'); + + const now = /** @type {string} */ (await page.locator('span').textContent()); + + await page.locator('[data-id="activate"]').click(); + await expect(page.locator('p')).toHaveText('active: true'); + + await page.locator('[data-id="invalidateAll"]').click(); + await page.evaluate(() => window.promise); + await expect(page.locator('p')).toHaveText('active: false'); + await expect(page.locator('span')).not.toHaveText(now); + }); }); test.describe('reroute', () => { @@ -1811,7 +1871,7 @@ test.describe('reroute', () => { expect(await page.textContent('h1')).toContain('Full Navigation'); }); - test('reroute works with invalidate', async ({ page }) => { + test('reroute works with refresh', async ({ page }) => { await page.goto('/reroute/invalidate/a'); await page.click('button'); await expect(page.locator('p')).toHaveText('data request: true'); diff --git a/packages/kit/test/apps/basics/test/test.js b/packages/kit/test/apps/basics/test/test.js index 25ffbe4ced36..b6dac3ac1f07 100644 --- a/packages/kit/test/apps/basics/test/test.js +++ b/packages/kit/test/apps/basics/test/test.js @@ -1078,7 +1078,7 @@ test.describe('Actions', () => { } }); - test('form prop stays after invalidation and is reset on navigation', async ({ + test('form prop stays after refresh and is reset on navigation', async ({ page, app, javaScriptEnabled @@ -1090,7 +1090,7 @@ test.describe('Actions', () => { await page.locator('button.increment-success').click(); await expect(page.locator('pre')).toHaveText(JSON.stringify({ count: 0 })); - await page.locator('button.invalidateAll').click(); + await page.locator('button.refreshAll').click(); await page.waitForTimeout(500); await expect(page.locator('pre')).toHaveText(JSON.stringify({ count: 0 })); await app.goto('/actions/enhance'); diff --git a/packages/kit/test/setup.js b/packages/kit/test/setup.js index d6d34f54a815..983e0a021dd3 100644 --- a/packages/kit/test/setup.js +++ b/packages/kit/test/setup.js @@ -1,6 +1,7 @@ import { goto, invalidate, + refresh, preloadCode, preloadData, beforeNavigate, @@ -14,6 +15,7 @@ export function setup() { Object.assign(window, { goto, invalidate, + refresh, preloadCode, preloadData, beforeNavigate, diff --git a/packages/kit/test/types.d.ts b/packages/kit/test/types.d.ts index dfe41a22eb17..bb9c60c73225 100644 --- a/packages/kit/test/types.d.ts +++ b/packages/kit/test/types.d.ts @@ -16,6 +16,7 @@ export const test: TestType< app: { goto(url: string, opts?: { replaceState?: boolean }): Promise; invalidate(url: string): Promise; + refresh(url: string): 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..30a29c852080 100644 --- a/packages/kit/test/utils.js +++ b/packages/kit/test/utils.js @@ -20,6 +20,8 @@ export const test = base.extend({ invalidate: (url) => page.evaluate((url) => invalidate(url), url), + refresh: (url) => page.evaluate((url) => refresh(url), url), + beforeNavigate: (fn) => page.evaluate((fn) => beforeNavigate(fn), fn), afterNavigate: () => page.evaluate(() => afterNavigate(() => {})), diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 318380ee4e5a..fe625eb43f49 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -1112,7 +1112,7 @@ declare module '@sveltejs/kit' { */ parent: () => Promise; /** - * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. + * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`refresh()`](https://svelte.dev/docs/kit/$app-navigation#refresh) to cause `load` to rerun. * * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. * @@ -1120,7 +1120,7 @@ declare module '@sveltejs/kit' { * * Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the [URI specification](https://www.rfc-editor.org/rfc/rfc3986.html). * - * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`d after a button click, making the `load` function rerun. + * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `refresh`ed after a button click, making the `load` function rerun. * * ```js * /// file: src/routes/+page.js @@ -1135,12 +1135,12 @@ declare module '@sveltejs/kit' { * ```html * /// file: src/routes/+page.svelte * * @@ -1783,7 +1783,7 @@ declare module '@sveltejs/kit' { */ parent: () => Promise; /** - * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. + * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`refresh()`](https://svelte.dev/docs/kit/$app-navigation#refresh) to cause `load` to rerun. * * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. * @@ -1791,7 +1791,7 @@ declare module '@sveltejs/kit' { * * Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the [URI specification](https://www.rfc-editor.org/rfc/rfc3986.html). * - * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`d after a button click, making the `load` function rerun. + * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `refresh`ed after a button click, making the `load` function rerun. * * ```js * /// file: src/routes/+page.js @@ -1806,12 +1806,12 @@ declare module '@sveltejs/kit' { * ```html * /// file: src/routes/+page.svelte * * @@ -3380,20 +3380,44 @@ declare module '$app/navigation' { * * invalidate((url) => url.pathname === '/path'); * ``` + * + * Note that this resets `page.state` to an empty object. If you want to preserve `page.state` (for example when using [shallow routing](https://svelte.dev/docs/kit/shallow-routing)), use `refresh` instead. + * + * @deprecated Use [`refresh`](https://svelte.dev/docs/kit/$app-navigation#refresh) instead. Unlike `invalidate`, `refresh` does not reset `page.state`. * @param resource The invalidated URL * */ export function invalidate(resource: string | URL | ((url: URL) => boolean)): Promise; + /** + * Causes any `load` functions belonging to the currently active page to re-run if they depend on the `url` in question, via `fetch` or `depends`. Returns a `Promise` that resolves when the page is subsequently updated. + * + * If the argument is given as a `string` or `URL`, it must resolve to the same URL that was passed to `fetch` or `depends` (including query parameters). + * To create a custom identifier, use a string beginning with `[a-z]+:` (e.g. `custom:state`) — this is a valid URL. + * + * The `function` argument can be used define a custom predicate. It receives the full `URL` and causes `load` to rerun if `true` is returned. + * This can be useful if you want to invalidate based on a pattern instead of a exact match. + * + * ```ts + * // Example: Match '/path' regardless of the query parameters + * import { refresh } from '$app/navigation'; + * + * refresh((url) => url.pathname === '/path'); + * ``` + * @param resource The invalidated URL + * */ + export function refresh(resource: string | URL | ((url: URL) => 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. + * + * Note that this resets `page.state` to an empty object. If you want to preserve `page.state` (for example when using [shallow routing](https://svelte.dev/docs/kit/shallow-routing)), use `refreshAll` instead. + * + * @deprecated Use [`refreshAll`](https://svelte.dev/docs/kit/$app-navigation#refreshAll) instead. Unlike `invalidateAll`, `refreshAll` does not reset `page.state`. * */ export function invalidateAll(): 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). + * Causes all currently active remote functions to refresh, and 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 refreshAll({ includeLoadFunctions }?: { - includeLoadFunctions?: boolean; - }): Promise; + export function refreshAll(): Promise; /** * Programmatically preloads the given page, which means * 1. ensuring that the code for the page is loaded, and From eb91d3754049ff15d5a267d552285fafeb77ddcd Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Thu, 9 Jul 2026 14:29:27 +0200 Subject: [PATCH 2/8] every. single. time --- packages/kit/types/index.d.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index fe625eb43f49..083dd006ef60 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -3361,6 +3361,8 @@ declare module '$app/navigation' { replaceState?: boolean | undefined; noScroll?: boolean | undefined; keepFocus?: boolean | undefined; + refreshAll?: boolean | undefined; + refresh?: (string | URL | ((url: URL) => boolean))[] | undefined; invalidateAll?: boolean | undefined; invalidate?: (string | URL | ((url: URL) => boolean))[] | undefined; state?: App.PageState | undefined; From faaf5942184ae16959f1da1df625c72794bbdb26 Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 10 Jul 2026 00:23:13 +0200 Subject: [PATCH 3/8] revert invalidate change --- packages/kit/src/runtime/app/navigation.js | 1 - packages/kit/src/runtime/client/client.js | 47 +++---------------- packages/kit/test/ambient.d.ts | 1 - .../load/cache-control/bust/+page.svelte | 4 +- .../load/cache-control/default/+page.svelte | 4 +- .../load/cache-control/force/+page.svelte | 4 +- .../change-detection/one/[x]/+page.svelte | 6 +-- .../load/invalidation/depends/+page.svelte | 14 +++--- .../invalidate-then-goto/+page.svelte | 8 ++-- .../multiple-batched/+page.svelte | 8 ++-- .../load/invalidation/multiple/+layout.svelte | 4 +- .../shallow-routing/refresh/+page.svelte | 3 +- .../kit/test/apps/basics/test/client.test.js | 41 +++++----------- packages/kit/test/setup.js | 2 - packages/kit/test/types.d.ts | 1 - packages/kit/test/utils.js | 2 - packages/kit/types/index.d.ts | 28 ++--------- 17 files changed, 50 insertions(+), 128 deletions(-) diff --git a/packages/kit/src/runtime/app/navigation.js b/packages/kit/src/runtime/app/navigation.js index f191ca51aca5..dd210cdb5fd3 100644 --- a/packages/kit/src/runtime/app/navigation.js +++ b/packages/kit/src/runtime/app/navigation.js @@ -5,7 +5,6 @@ export { goto, invalidate, invalidateAll, - refresh, refreshAll, onNavigate, preloadCode, diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 8f7361f17d66..65b6ef69de14 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -523,7 +523,7 @@ function persist_state() { /** * @param {string | URL} url - * @param {{ replaceState?: boolean; noScroll?: boolean; keepFocus?: boolean; refreshAll?: boolean; refresh?: Array boolean)>; state?: Record }} options + * @param {{ replaceState?: boolean; noScroll?: boolean; keepFocus?: boolean; refreshAll?: boolean; invalidate?: Array boolean)>; state?: Record }} options * @param {number} redirect_count * @param {{}} [nav_token] * @param {NavigationIntent | undefined} [intent] navigation intent, when already known by the caller (avoids recomputing it) @@ -572,8 +572,8 @@ export async function _goto(url, options, redirect_count, nav_token, intent) { } } - if (options.refresh) { - options.refresh.forEach(push_invalidated); + if (options.invalidate) { + options.invalidate.forEach(push_invalidated); } } }); @@ -2307,9 +2307,8 @@ export function disableScrollHandling() { * @param {boolean} [opts.noScroll] If `true`, the browser will maintain its scroll position rather than scrolling to the top of the page after navigation * @param {boolean} [opts.keepFocus] If `true`, the currently focused element will retain focus after navigation. Otherwise, focus will be reset to the body * @param {boolean} [opts.refreshAll] If `true`, all `load` functions and queries of the page will be rerun. See https://svelte.dev/docs/kit/load#rerunning-load-functions for more info on invalidation. - * @param {Array boolean)>} [opts.refresh] Causes any load functions to re-run if they depend on one of the urls + * @param {Array boolean)>} [opts.invalidate] Causes any load functions to re-run if they depend on one of the urls * @param {boolean} [opts.invalidateAll] Deprecated in favor of opts.refreshAll. - * @param {Array boolean)>} [opts.invalidate] Deprecated in favor of opts.refresh. * @param {App.PageState} [opts.state] An optional object that will be available as `page.state` * @returns {Promise} */ @@ -2338,7 +2337,6 @@ export async function goto(url, opts = {}) { ); } - opts.refresh = opts.refresh ?? opts.invalidate; opts.refreshAll = opts.refreshAll ?? opts.invalidateAll; return _goto(url, opts, 0, {}, intent); } @@ -2358,49 +2356,18 @@ export async function goto(url, opts = {}) { * * invalidate((url) => url.pathname === '/path'); * ``` - * - * Note that this resets `page.state` to an empty object. If you want to preserve `page.state` (for example when using [shallow routing](https://svelte.dev/docs/kit/shallow-routing)), use `refresh` instead. - * - * @deprecated Use [`refresh`](https://svelte.dev/docs/kit/$app-navigation#refresh) instead. Unlike `invalidate`, `refresh` does not reset `page.state`. * @param {string | URL | ((url: URL) => boolean)} resource The invalidated URL + * @param {boolean} [keep_state] If `true` (the default), the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. * @returns {Promise} */ -export function invalidate(resource) { +export function invalidate(resource, keep_state = false) { if (!BROWSER) { throw new Error('Cannot call invalidate(...) on the server'); } push_invalidated(resource); - return _invalidate(); -} - -/** - * Causes any `load` functions belonging to the currently active page to re-run if they depend on the `url` in question, via `fetch` or `depends`. Returns a `Promise` that resolves when the page is subsequently updated. - * - * If the argument is given as a `string` or `URL`, it must resolve to the same URL that was passed to `fetch` or `depends` (including query parameters). - * To create a custom identifier, use a string beginning with `[a-z]+:` (e.g. `custom:state`) — this is a valid URL. - * - * The `function` argument can be used define a custom predicate. It receives the full `URL` and causes `load` to rerun if `true` is returned. - * This can be useful if you want to invalidate based on a pattern instead of a exact match. - * - * ```ts - * // Example: Match '/path' regardless of the query parameters - * import { refresh } from '$app/navigation'; - * - * refresh((url) => url.pathname === '/path'); - * ``` - * @param {string | URL | ((url: URL) => boolean)} resource The invalidated URL - * @returns {Promise} - */ -export function refresh(resource) { - if (!BROWSER) { - throw new Error('Cannot call refresh(...) on the server'); - } - - push_invalidated(resource); - - return _invalidate(false); + return _invalidate(!keep_state); } /** diff --git a/packages/kit/test/ambient.d.ts b/packages/kit/test/ambient.d.ts index 44333f6ec518..6db31b75d90f 100644 --- a/packages/kit/test/ambient.d.ts +++ b/packages/kit/test/ambient.d.ts @@ -15,7 +15,6 @@ declare global { ) => Promise; const invalidate: (url: string) => Promise; - const refresh: (url: string) => 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/load/cache-control/bust/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/cache-control/bust/+page.svelte index 1f25d54a6472..357cb388c3d8 100644 --- a/packages/kit/test/apps/basics/src/routes/load/cache-control/bust/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/cache-control/bust/+page.svelte @@ -1,5 +1,5 @@ diff --git a/packages/kit/test/apps/basics/src/routes/load/cache-control/default/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/cache-control/default/+page.svelte index aab9aee2a828..f9ee117d09ac 100644 --- a/packages/kit/test/apps/basics/src/routes/load/cache-control/default/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/cache-control/default/+page.svelte @@ -1,5 +1,5 @@ diff --git a/packages/kit/test/apps/basics/src/routes/load/cache-control/force/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/cache-control/force/+page.svelte index 49599729d365..5f243b2206b6 100644 --- a/packages/kit/test/apps/basics/src/routes/load/cache-control/force/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/cache-control/force/+page.svelte @@ -1,12 +1,12 @@ diff --git a/packages/kit/test/apps/basics/src/routes/load/change-detection/one/[x]/+page.svelte b/packages/kit/test/apps/basics/src/routes/load/change-detection/one/[x]/+page.svelte index e4b68e69d42e..ff473717c549 100644 --- a/packages/kit/test/apps/basics/src/routes/load/change-detection/one/[x]/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/change-detection/one/[x]/+page.svelte @@ -1,5 +1,5 @@ @@ -9,11 +9,11 @@ id="multiple-batched" onclick={(event) => { const btn = event.currentTarget; - refresh('multiple:invalidations-go-brr'); - refresh('multiple:invalidations-go-brr'); + invalidate('multiple:invalidations-go-brr'); + invalidate('multiple:invalidations-go-brr'); Promise.resolve() - .then(() => refresh('multiple:invalidations-go-brr')) + .then(() => invalidate('multiple:invalidations-go-brr')) .then(() => { btn.dataset.done = 'true'; }); diff --git a/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/+layout.svelte b/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/+layout.svelte index 782fe9535895..42b36837895a 100644 --- a/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/+layout.svelte +++ b/packages/kit/test/apps/basics/src/routes/load/invalidation/multiple/+layout.svelte @@ -1,5 +1,5 @@ diff --git a/packages/kit/test/apps/basics/src/routes/shallow-routing/refresh/+page.svelte b/packages/kit/test/apps/basics/src/routes/shallow-routing/refresh/+page.svelte index fb5d76bc3c65..ea3961aba72e 100644 --- a/packages/kit/test/apps/basics/src/routes/shallow-routing/refresh/+page.svelte +++ b/packages/kit/test/apps/basics/src/routes/shallow-routing/refresh/+page.svelte @@ -1,5 +1,5 @@ @@ -690,7 +690,7 @@ To summarize, a `load` function will rerun in the following situations: - It calls `url.searchParams.get(...)`, `url.searchParams.getAll(...)` or `url.searchParams.has(...)` and the parameter in question changes. Accessing other properties of `url.searchParams` will have the same effect as accessing `url.search`. - It calls `await parent()` and a parent `load` function reran - A child `load` function calls `await parent()` and is rerunning, and the parent is a server load function -- It declared a dependency on a specific URL via [`fetch`](#Making-fetch-requests) (universal load only) or [`depends`](@sveltejs-kit#LoadEvent), and that URL was marked invalid with [`refresh(url)`]($app-navigation#refresh) +- It declared a dependency on a specific URL via [`fetch`](#Making-fetch-requests) (universal load only) or [`depends`](@sveltejs-kit#LoadEvent), and that URL was marked invalid with [`invalidate(url)`]($app-navigation#invalidate) - All active `load` functions were forcibly rerun with [`refreshAll()`]($app-navigation#refreshAll) `params` and `url` can change in response to a `` link click, a [`` interaction](form-actions#GET-vs-POST), a [`goto`]($app-navigation#goto) invocation, or a [`redirect`](@sveltejs-kit#redirect). diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 3f78b00cf7ab..3a21d239358f 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -1139,7 +1139,7 @@ export interface LoadEvent< */ parent: () => Promise; /** - * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`refresh()`](https://svelte.dev/docs/kit/$app-navigation#refresh) to cause `load` to rerun. + * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. * * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. * @@ -1147,7 +1147,7 @@ export interface LoadEvent< * * Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the [URI specification](https://www.rfc-editor.org/rfc/rfc3986.html). * - * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `refresh`ed after a button click, making the `load` function rerun. + * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`ed after a button click, making the `load` function rerun. * * ```js * /// file: src/routes/+page.js @@ -1162,12 +1162,12 @@ export interface LoadEvent< * ```html * /// file: src/routes/+page.svelte * * diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 65b6ef69de14..d25fc3a8801b 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -2357,7 +2357,7 @@ export async function goto(url, opts = {}) { * invalidate((url) => url.pathname === '/path'); * ``` * @param {string | URL | ((url: URL) => boolean)} resource The invalidated URL - * @param {boolean} [keep_state] If `true` (the default), the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. + * @param {boolean} [keep_state] If `true`, the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. `false` by default. * @returns {Promise} */ export function invalidate(resource, keep_state = false) { diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 4feb304df49e..1e4833e9c583 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -1112,7 +1112,7 @@ declare module '@sveltejs/kit' { */ parent: () => Promise; /** - * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`refresh()`](https://svelte.dev/docs/kit/$app-navigation#refresh) to cause `load` to rerun. + * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. * * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. * @@ -1120,7 +1120,7 @@ declare module '@sveltejs/kit' { * * Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the [URI specification](https://www.rfc-editor.org/rfc/rfc3986.html). * - * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `refresh`ed after a button click, making the `load` function rerun. + * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`ed after a button click, making the `load` function rerun. * * ```js * /// file: src/routes/+page.js @@ -1135,12 +1135,12 @@ declare module '@sveltejs/kit' { * ```html * /// file: src/routes/+page.svelte * * @@ -3382,7 +3382,7 @@ declare module '$app/navigation' { * invalidate((url) => url.pathname === '/path'); * ``` * @param resource The invalidated URL - * @param keep_state If `true` (the default), the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. + * @param keep_state If `true`, the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. `false` by default. * */ export function invalidate(resource: string | URL | ((url: URL) => boolean), keep_state?: boolean): Promise; /** From e111e0627ef1ecc05b86454955a021840a46255c Mon Sep 17 00:00:00 2001 From: Simon Holthausen Date: Fri, 10 Jul 2026 01:16:59 +0200 Subject: [PATCH 5/8] fix --- packages/kit/test/apps/basics/test/client.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kit/test/apps/basics/test/client.test.js b/packages/kit/test/apps/basics/test/client.test.js index 0f0b4803120b..c9a069649f35 100644 --- a/packages/kit/test/apps/basics/test/client.test.js +++ b/packages/kit/test/apps/basics/test/client.test.js @@ -76,7 +76,7 @@ test.describe('Load', () => { expect(await page.textContent('h1')).toBe('layout loads: 5'); expect(await page.textContent('h2')).toBe('x: b: 3'); - await page.click('button:has-text("invalidate all")'); + await page.click('button:has-text("refresh all")'); await page.waitForFunction('window.invalidated'); expect(await page.textContent('h1')).toBe('layout loads: 6'); expect(await page.textContent('h2')).toBe('x: b: 4'); @@ -1679,7 +1679,7 @@ test.describe('Shallow routing', () => { await page.locator('[data-id="two"]').click(); expect(page.url()).toBe(`${baseURL}/shallow-routing/push-state/a`); - await page.locator('[data-id="invalidate"]').click(); + await page.locator('[data-id="refresh"]').click(); await expect(page.locator('h1')).toHaveText('parent'); await expect(page.locator('span')).not.toHaveText(now); }); From 7b298233142ae41fca549034ab5d5d728c4dc660 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 10 Jul 2026 12:29:57 -0400 Subject: [PATCH 6/8] Apply suggestions from code review Co-authored-by: Tee Ming --- .changeset/refresh-page-state.md | 2 +- packages/kit/src/exports/public.d.ts | 10 +++++----- packages/kit/src/runtime/client/client.js | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.changeset/refresh-page-state.md b/.changeset/refresh-page-state.md index d228238ee0e2..f69d1876700a 100644 --- a/.changeset/refresh-page-state.md +++ b/.changeset/refresh-page-state.md @@ -2,4 +2,4 @@ '@sveltejs/kit': major --- -breaking: add `refresh`/`refreshAll` and deprecate `invalidate`/`invalidateAll` +breaking: add `refreshAll` and deprecate `invalidateAll` diff --git a/packages/kit/src/exports/public.d.ts b/packages/kit/src/exports/public.d.ts index 3a21d239358f..66847e93e808 100644 --- a/packages/kit/src/exports/public.d.ts +++ b/packages/kit/src/exports/public.d.ts @@ -1147,7 +1147,7 @@ export interface LoadEvent< * * Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the [URI specification](https://www.rfc-editor.org/rfc/rfc3986.html). * - * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`ed after a button click, making the `load` function rerun. + * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`d after a button click, making the `load` function rerun. * * ```js * /// file: src/routes/+page.js @@ -1812,7 +1812,7 @@ export interface ServerLoadEvent< */ parent: () => Promise; /** - * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`refresh()`](https://svelte.dev/docs/kit/$app-navigation#refresh) to cause `load` to rerun. + * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. * * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. * @@ -1820,7 +1820,7 @@ export interface ServerLoadEvent< * * Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the [URI specification](https://www.rfc-editor.org/rfc/rfc3986.html). * - * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `refresh`ed after a button click, making the `load` function rerun. + * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`d after a button click, making the `load` function rerun. * * ```js * /// file: src/routes/+page.js @@ -1835,12 +1835,12 @@ export interface ServerLoadEvent< * ```html * /// file: src/routes/+page.svelte * * diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index d25fc3a8801b..8b399556a6f5 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -2308,7 +2308,7 @@ export function disableScrollHandling() { * @param {boolean} [opts.keepFocus] If `true`, the currently focused element will retain focus after navigation. Otherwise, focus will be reset to the body * @param {boolean} [opts.refreshAll] If `true`, all `load` functions and queries of the page will be rerun. See https://svelte.dev/docs/kit/load#rerunning-load-functions for more info on invalidation. * @param {Array boolean)>} [opts.invalidate] Causes any load functions to re-run if they depend on one of the urls - * @param {boolean} [opts.invalidateAll] Deprecated in favor of opts.refreshAll. + * @param {boolean} [opts.invalidateAll] Deprecated in favour of opts.refreshAll. * @param {App.PageState} [opts.state] An optional object that will be available as `page.state` * @returns {Promise} */ @@ -2357,17 +2357,17 @@ export async function goto(url, opts = {}) { * invalidate((url) => url.pathname === '/path'); * ``` * @param {string | URL | ((url: URL) => boolean)} resource The invalidated URL - * @param {boolean} [keep_state] If `true`, the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. `false` by default. + * @param {boolean} [keepState] If `true`, the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. `false` by default. * @returns {Promise} */ -export function invalidate(resource, keep_state = false) { +export function invalidate(resource, keepState = false) { if (!BROWSER) { throw new Error('Cannot call invalidate(...) on the server'); } push_invalidated(resource); - return _invalidate(!keep_state); + return _invalidate(!keepState); } /** From d15356b86c4541b45e93e974e9fad7deb5dbcc8d Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 10 Jul 2026 12:47:53 -0400 Subject: [PATCH 7/8] regenerate --- packages/kit/types/index.d.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/kit/types/index.d.ts b/packages/kit/types/index.d.ts index 1e4833e9c583..1ac57eb7a3af 100644 --- a/packages/kit/types/index.d.ts +++ b/packages/kit/types/index.d.ts @@ -1120,7 +1120,7 @@ declare module '@sveltejs/kit' { * * Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the [URI specification](https://www.rfc-editor.org/rfc/rfc3986.html). * - * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`ed after a button click, making the `load` function rerun. + * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`d after a button click, making the `load` function rerun. * * ```js * /// file: src/routes/+page.js @@ -1783,7 +1783,7 @@ declare module '@sveltejs/kit' { */ parent: () => Promise; /** - * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`refresh()`](https://svelte.dev/docs/kit/$app-navigation#refresh) to cause `load` to rerun. + * This function declares that the `load` function has a _dependency_ on one or more URLs or custom identifiers, which can subsequently be used with [`invalidate()`](https://svelte.dev/docs/kit/$app-navigation#invalidate) to cause `load` to rerun. * * Most of the time you won't need this, as `fetch` calls `depends` on your behalf — it's only necessary if you're using a custom API client that bypasses `fetch`. * @@ -1791,7 +1791,7 @@ declare module '@sveltejs/kit' { * * Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the [URI specification](https://www.rfc-editor.org/rfc/rfc3986.html). * - * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `refresh`ed after a button click, making the `load` function rerun. + * The following example shows how to use `depends` to register a dependency on a custom identifier, which is `invalidate`d after a button click, making the `load` function rerun. * * ```js * /// file: src/routes/+page.js @@ -1806,12 +1806,12 @@ declare module '@sveltejs/kit' { * ```html * /// file: src/routes/+page.svelte * * @@ -3382,9 +3382,9 @@ declare module '$app/navigation' { * invalidate((url) => url.pathname === '/path'); * ``` * @param resource The invalidated URL - * @param keep_state If `true`, the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. `false` by default. + * @param keepState If `true`, the current `page.state` will be preserved. Otherwise, it will be reset to an empty object. `false` by default. * */ - export function invalidate(resource: string | URL | ((url: URL) => boolean), keep_state?: boolean): Promise; + export function invalidate(resource: string | URL | ((url: URL) => boolean), keepState?: 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. * From 9851cce2901cdfc261c932660b268aed4ec38378 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Fri, 10 Jul 2026 13:28:56 -0400 Subject: [PATCH 8/8] add warning --- packages/kit/src/runtime/client/client.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 8b399556a6f5..34b6750a9bc9 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -2293,6 +2293,8 @@ export function disableScrollHandling() { } } +let warned_on_invalidate_all = false; + /** * Allows you to navigate programmatically to a given route, with options such as keeping the current element focused. * Returns a Promise that resolves when SvelteKit navigates (or fails to navigate, in which case the promise rejects) to the specified `url`. @@ -2337,6 +2339,13 @@ export async function goto(url, opts = {}) { ); } + if (DEV && 'invalidateAll' in opts && !warned_on_invalidate_all) { + warned_on_invalidate_all = true; + console.warn( + `The \`goto(..., { invalidateAll: ${opts.invalidateAll} })\` option has been deprecated in favour of \`refreshAll\`` + ); + } + opts.refreshAll = opts.refreshAll ?? opts.invalidateAll; return _goto(url, opts, 0, {}, intent); }