diff --git a/.changeset/ninety-tables-switch.md b/.changeset/ninety-tables-switch.md new file mode 100644 index 000000000000..37bd6b1f8937 --- /dev/null +++ b/.changeset/ninety-tables-switch.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +[breaking] call `invalidate(fn)` predicates with a URL instead of a string diff --git a/.changeset/rude-nails-work.md b/.changeset/rude-nails-work.md new file mode 100644 index 000000000000..e11a00cbf10b --- /dev/null +++ b/.changeset/rude-nails-work.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +[breaking] replace invalidate() with invalidateAll() diff --git a/.changeset/shiny-vans-jam.md b/.changeset/shiny-vans-jam.md new file mode 100644 index 000000000000..84664ebdbab8 --- /dev/null +++ b/.changeset/shiny-vans-jam.md @@ -0,0 +1,5 @@ +--- +'create-svelte': patch +--- + +Use `invalidateAll()` diff --git a/documentation/docs/05-load.md b/documentation/docs/05-load.md index eb83c9111ec0..0aaf5389dffc 100644 --- a/documentation/docs/05-load.md +++ b/documentation/docs/05-load.md @@ -99,12 +99,14 @@ An instance of [`URL`](https://developer.mozilla.org/en-US/docs/Web/API/URL), co #### depends -This function declares that the `load` function has a _dependency_ on one or more URLs, which can subsequently be used with [`invalidate()`](/docs/modules#$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 [`invalidate()`](/docs/modules#$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`. URLs can be absolute or relative to the page being loaded, and must be [encoded](https://developer.mozilla.org/en-US/docs/Glossary/percent-encoding). +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) + ```js // @filename: ambient.d.ts declare module '$lib/api' { @@ -121,7 +123,11 @@ import * as api from '$lib/api'; /** @type {import('./$types').PageLoad} */ export async function load({ depends }) { - depends(`${api.base}/foo`, `${api.base}/bar`); + depends( + `${api.base}/foo`, + `${api.base}/bar`, + 'my-stuff:foo' + ); return { foo: api.client.get('/foo'), diff --git a/packages/create-svelte/templates/default/src/lib/form.ts b/packages/create-svelte/templates/default/src/lib/form.ts index c38dee6ec094..6723c612f5de 100644 --- a/packages/create-svelte/templates/default/src/lib/form.ts +++ b/packages/create-svelte/templates/default/src/lib/form.ts @@ -1,4 +1,4 @@ -import { invalidate } from '$app/navigation'; +import { invalidateAll } from '$app/navigation'; // this action (https://svelte.dev/tutorial/actions) allows us to // progressively enhance a
that already works without JS @@ -83,7 +83,7 @@ export function enhance( if (response.ok) { if (result) result({ data, form, response }); - invalidate(); + invalidateAll(); } else if (error) { error({ data, form, error: null, response }); } else { diff --git a/packages/kit/src/runtime/app/navigation.js b/packages/kit/src/runtime/app/navigation.js index d97e6dea6629..974e83a13e90 100644 --- a/packages/kit/src/runtime/app/navigation.js +++ b/packages/kit/src/runtime/app/navigation.js @@ -16,6 +16,7 @@ export const disableScrollHandling = ssr : client.disable_scroll_handling; export const goto = ssr ? guard('goto') : client.goto; export const invalidate = ssr ? guard('invalidate') : client.invalidate; +export const invalidateAll = ssr ? guard('invalidateAll') : client.invalidateAll; export const prefetch = ssr ? guard('prefetch') : client.prefetch; export const prefetchRoutes = ssr ? guard('prefetchRoutes') : client.prefetch_routes; export const beforeNavigate = ssr ? () => {} : client.before_navigate; diff --git a/packages/kit/src/runtime/client/client.js b/packages/kit/src/runtime/client/client.js index 6b95fbbfd1a7..190348e840c1 100644 --- a/packages/kit/src/runtime/client/client.js +++ b/packages/kit/src/runtime/client/client.js @@ -70,7 +70,7 @@ function check_for_removed_attributes() { * @returns {import('./types').Client} */ export function create_client({ target, base, trailing_slash }) { - /** @type {Array<((href: string) => boolean)>} */ + /** @type {Array<((url: URL) => boolean)>} */ const invalidated = []; /** @type {{id: string | null, promise: Promise | null}} */ @@ -103,6 +103,7 @@ export function create_client({ target, base, trailing_slash }) { /** @type {Promise | null} */ let invalidating = null; + let force_invalidation = false; /** @type {import('svelte').SvelteComponent} */ let root; @@ -139,6 +140,19 @@ export function create_client({ target, base, trailing_slash }) { /** @type {{}} */ let token; + function invalidate() { + if (!invalidating) { + invalidating = Promise.resolve().then(async () => { + await update(new URL(location.href), []); + + invalidating = null; + force_invalidation = false; + }); + } + + return invalidating; + } + /** * @param {string | URL} url * @param {{ noscroll?: boolean; replaceState?: boolean; keepfocus?: boolean; state?: any }} opts @@ -639,6 +653,8 @@ export function create_client({ target, base, trailing_slash }) { * @param {{ url: boolean, params: string[] }} changed */ function has_changed(changed, parent_changed, uses) { + if (force_invalidation) return true; + if (!uses) return false; if (uses.parent && parent_changed) return true; @@ -648,8 +664,8 @@ export function create_client({ target, base, trailing_slash }) { if (uses.params.has(param)) return true; } - for (const dep of uses.dependencies) { - if (invalidated.some((fn) => fn(dep))) return true; + for (const href of uses.dependencies) { + if (invalidated.some((fn) => fn(new URL(href)))) return true; } return false; @@ -1057,28 +1073,25 @@ export function create_client({ target, base, trailing_slash }) { invalidate: (resource) => { if (resource === undefined) { - // Force rerun of all load functions, regardless of their dependencies - for (const node of current.branch) { - node?.server?.uses.dependencies.add(''); - node?.shared?.uses.dependencies.add(''); - } - invalidated.push(() => true); - } else if (typeof resource === 'function') { + // TODO remove for 1.0 + throw new Error( + '`invalidate()` (with no arguments) has been replaced by `invalidateAll()`' + ); + } + + if (typeof resource === 'function') { invalidated.push(resource); } else { const { href } = new URL(resource, location.href); - invalidated.push((dep) => dep === href); + invalidated.push((url) => url.href === href); } - if (!invalidating) { - invalidating = Promise.resolve().then(async () => { - await update(new URL(location.href), []); - - invalidating = null; - }); - } + return invalidate(); + }, - return invalidating; + invalidateAll: () => { + force_invalidation = true; + return invalidate(); }, prefetch: async (href) => { diff --git a/packages/kit/src/runtime/client/types.d.ts b/packages/kit/src/runtime/client/types.d.ts index e86bc3ae0eb2..f2f5a3617d01 100644 --- a/packages/kit/src/runtime/client/types.d.ts +++ b/packages/kit/src/runtime/client/types.d.ts @@ -3,6 +3,7 @@ import { beforeNavigate, goto, invalidate, + invalidateAll, prefetch, prefetchRoutes } from '$app/navigation'; @@ -17,6 +18,7 @@ export interface Client { disable_scroll_handling: () => void; goto: typeof goto; invalidate: typeof invalidate; + invalidateAll: typeof invalidateAll; prefetch: typeof prefetch; prefetch_routes: typeof prefetchRoutes; 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 9acf3f2212f9..11134eaf5433 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 @@