async function load_route()

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,
		});
	}