-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat: allow for fine grained invalidation of search params #11066
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 24 commits
364c2a4
988bcb6
0e51f81
47b7b9b
ac11e75
d3b4d2f
e0c67f8
fe6b814
4968f42
5373dfa
ad8d2c6
bbc62f1
5b6b253
d3a9ae8
8fc1328
d470608
9e04dad
92c45f2
e8bb9f1
f4975dd
6172001
51c20ab
23ea3f5
56b50d5
d72cac9
ff8b4bb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@sveltejs/kit": minor | ||
| --- | ||
|
|
||
| feat: allow for fine grained invalidation of search params |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,9 +69,10 @@ function native_navigation(url) { | |
| /** | ||
| * @param {import('./types.js').SvelteKitApp} app | ||
| * @param {HTMLElement} target | ||
| * @param {boolean} fine_grained_search_params_invalidation | ||
| * @returns {import('./types.js').Client} | ||
| */ | ||
| export function create_client(app, target) { | ||
| export function create_client(app, target, fine_grained_search_params_invalidation) { | ||
|
||
| const routes = parse(app); | ||
|
|
||
| const default_layout_loader = app.nodes[0]; | ||
|
|
@@ -443,7 +444,8 @@ export function create_client(app, target) { | |
| params: new Set(), | ||
| parent: false, | ||
| route: false, | ||
| url: false | ||
| url: false, | ||
| search_params: new Set() | ||
| }; | ||
|
|
||
| const node = await loader(); | ||
|
|
@@ -478,9 +480,19 @@ export function create_client(app, target) { | |
| } | ||
| }), | ||
| data: server_data_node?.data ?? null, | ||
| url: make_trackable(url, () => { | ||
| uses.url = true; | ||
| }), | ||
| url: make_trackable( | ||
| url, | ||
| () => { | ||
| uses.url = true; | ||
| }, | ||
| (search_param) => { | ||
| if (fine_grained_search_params_invalidation) { | ||
| uses.search_params.add(search_param); | ||
| } else { | ||
| uses.url = true; | ||
| } | ||
| } | ||
| ), | ||
| async fetch(resource, init) { | ||
| /** @type {URL | string} */ | ||
| let requested; | ||
|
|
@@ -576,10 +588,18 @@ export function create_client(app, target) { | |
| * @param {boolean} parent_changed | ||
| * @param {boolean} route_changed | ||
| * @param {boolean} url_changed | ||
| * @param {Set<string>} search_params_changed | ||
| * @param {import('types').Uses | undefined} uses | ||
| * @param {Record<string, string>} params | ||
| */ | ||
| function has_changed(parent_changed, route_changed, url_changed, uses, params) { | ||
| function has_changed( | ||
| parent_changed, | ||
| route_changed, | ||
| url_changed, | ||
| search_params_changed, | ||
| uses, | ||
| params | ||
| ) { | ||
| if (force_invalidation) return true; | ||
|
|
||
| if (!uses) return false; | ||
|
|
@@ -588,6 +608,10 @@ export function create_client(app, target) { | |
| if (uses.route && route_changed) return true; | ||
| if (uses.url && url_changed) return true; | ||
|
|
||
| for (const tracked_params of uses.search_params) { | ||
| if (search_params_changed.has(tracked_params)) return true; | ||
| } | ||
|
|
||
| for (const param of uses.params) { | ||
| if (params[param] !== current.params[param]) return true; | ||
| } | ||
|
|
@@ -610,6 +634,35 @@ export function create_client(app, target) { | |
| return null; | ||
| } | ||
|
|
||
| /** | ||
| * | ||
| * @param {URL} [old_url] | ||
| * @param {URL} [new_url] | ||
| */ | ||
| function check_search_params_changed(old_url, new_url) { | ||
| const changed = new Set(); | ||
| const new_search_params = new URLSearchParams(new_url?.searchParams); | ||
| const old_search_params = old_url?.searchParams; | ||
| for (const key of new Set(old_search_params?.keys?.() ?? [])) { | ||
| const new_get_all = new_search_params.getAll(key); | ||
| const old_get_all = old_search_params?.getAll?.(key) ?? []; | ||
| if ( | ||
| // check if the two arrays contains the same values | ||
| !( | ||
| new_get_all.every((query_param) => old_get_all.includes(query_param)) && | ||
| old_get_all.every((query_param) => new_get_all.includes(query_param)) | ||
| ) | ||
| ) { | ||
| changed.add(key); | ||
| } | ||
| new_search_params.delete(key); | ||
paoloricciuti marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| for (const [key] of new_search_params) { | ||
| changed.add(key); | ||
| } | ||
| return changed; | ||
| } | ||
|
|
||
| /** | ||
| * @param {import('./types.js').NavigationIntent} intent | ||
| * @returns {Promise<import('./types.js').NavigationResult>} | ||
|
|
@@ -631,9 +684,9 @@ export function create_client(app, target) { | |
|
|
||
| /** @type {import('types').ServerNodesResponse | import('types').ServerRedirectNode | null} */ | ||
| let server_data = null; | ||
|
|
||
| const url_changed = current.url ? id !== current.url.pathname + current.url.search : false; | ||
| const route_changed = current.route ? route.id !== current.route.id : false; | ||
| const search_params_changed = check_search_params_changed(current.url, url); | ||
|
|
||
| let parent_invalid = false; | ||
| const invalid_server_nodes = loaders.map((loader, i) => { | ||
|
|
@@ -642,7 +695,14 @@ export function create_client(app, target) { | |
| const invalid = | ||
| !!loader?.[0] && | ||
| (previous?.loader !== loader[1] || | ||
| has_changed(parent_invalid, route_changed, url_changed, previous.server?.uses, params)); | ||
| has_changed( | ||
| parent_invalid, | ||
| route_changed, | ||
| url_changed, | ||
| search_params_changed, | ||
| previous.server?.uses, | ||
| params | ||
| )); | ||
|
|
||
| if (invalid) { | ||
| // For the next one | ||
|
|
@@ -685,7 +745,14 @@ export function create_client(app, target) { | |
| const valid = | ||
| (!server_data_node || server_data_node.type === 'skip') && | ||
| loader[1] === previous?.loader && | ||
| !has_changed(parent_changed, route_changed, url_changed, previous.universal?.uses, params); | ||
| !has_changed( | ||
| parent_changed, | ||
| route_changed, | ||
| url_changed, | ||
| search_params_changed, | ||
| previous.universal?.uses, | ||
| params | ||
| ); | ||
| if (valid) return previous; | ||
|
|
||
| parent_changed = true; | ||
|
|
@@ -1954,7 +2021,8 @@ function deserialize_uses(uses) { | |
| params: new Set(uses?.params ?? []), | ||
| parent: !!uses?.parent, | ||
| route: !!uses?.route, | ||
| url: !!uses?.url | ||
| url: !!uses?.url, | ||
| search_params: new Set(uses?.search_params ?? []) | ||
| }; | ||
| } | ||
|
|
||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.