in kit/svelteKitCustomClient/client.js [627:802]
async function load_route({ id, invalidating, url, params, route }) {
if (load_cache?.id === id) {
return load_cache.promise;
}
const { errors, layouts, leaf } = route;
const loaders = [...layouts, leaf];
// preload modules to avoid waterfall, but handle rejections
// so they don't get reported to Sentry et al (we don't need
// to act on the failures at this point)
errors.forEach((loader) => loader?.().catch(() => {}));
loaders.forEach((loader) => loader?.[1]().catch(() => {}));
/** @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;
let parent_invalid = false;
const invalid_server_nodes = loaders.map((loader, i) => {
const previous = current.branch[i];
const invalid =
!!loader?.[0] &&
(previous?.loader !== loader[1] ||
has_changed(parent_invalid, route_changed, url_changed, previous.server?.uses, params));
if (invalid) {
// For the next one
parent_invalid = true;
}
return invalid;
});
if (invalid_server_nodes.some(Boolean)) {
try {
server_data = await load_data(url, invalid_server_nodes);
} catch (error) {
return load_root_error_page({
status: error instanceof HttpError ? error.status : 500,
error: await handle_error(error, { url, params, route: { id: route.id } }),
url,
route,
});
}
if (server_data.type === "redirect") {
return server_data;
}
}
const server_data_nodes = server_data?.nodes;
let parent_changed = false;
const branch_promises = loaders.map(async (loader, i) => {
if (!loader) return;
/** @type {import('./types').BranchNode | undefined} */
const previous = current.branch[i];
const server_data_node = server_data_nodes?.[i];
// re-use data from previous load if it's still valid
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);
if (valid) return previous;
parent_changed = true;
if (server_data_node?.type === "error") {
// rethrow and catch below
throw server_data_node;
}
return load_node({
loader: loader[1],
url,
params,
route,
parent: async () => {
const data = {};
for (let j = 0; j < i; j += 1) {
Object.assign(data, (await branch_promises[j])?.data);
}
return data;
},
server_data_node: create_data_node(
// server_data_node is undefined if it wasn't reloaded from the server;
// and if current loader uses server data, we want to reuse previous data.
server_data_node === undefined && loader[0] ? { type: "skip" } : server_data_node ?? null,
loader[0] ? previous?.server : undefined
),
});
});
// if we don't do this, rejections will be unhandled
for (const p of branch_promises) p.catch(() => {});
/** @type {Array<import('./types').BranchNode | undefined>} */
const branch = [];
for (let i = 0; i < loaders.length; i += 1) {
if (loaders[i]) {
try {
branch.push(await branch_promises[i]);
} catch (err) {
if (err instanceof Redirect) {
return {
type: "redirect",
location: err.location,
};
}
let status = 500;
/** @type {App.Error} */
let error;
if (server_data_nodes?.includes(/** @type {import('types').ServerErrorNode} */ (err))) {
// this is the server error rethrown above, reconstruct but don't invoke
// the client error handler; it should've already been handled on the server
status = /** @type {import('types').ServerErrorNode} */ (err).status ?? status;
error = /** @type {import('types').ServerErrorNode} */ (err).error;
} else if (err instanceof HttpError) {
status = err.status;
error = err.body;
} else {
// Referenced node could have been removed due to redeploy, check
const updated = await stores.updated.check();
if (updated) {
return await native_navigation(url);
}
error = await handle_error(err, { params, url, route: { id: route.id } });
}
const error_load = await load_nearest_error_page(i, branch, errors);
if (error_load) {
return await get_navigation_result_from_branch({
url,
params,
branch: branch.slice(0, error_load.idx).concat(error_load.node),
status,
error,
route,
});
} else {
// if we get here, it's because the root `load` function failed,
// and we need to fall back to the server
return await server_fallback(url, { id: route.id }, error, status);
}
}
} else {
// push an empty slot so we can rewind past gaps to the
// layout that corresponds with an +error.svelte page
branch.push(undefined);
}
}
return await get_navigation_result_from_branch({
url,
params,
branch,
status: 200,
error: null,
route,
// Reset `form` on navigation, but not invalidation
form: invalidating ? undefined : null,
});
}