Svelte / SvelteKitMiddleTechnical
В чём разница между функциями load в +page.ts и +page.server.ts?
+page.ts выполняется и на сервере (SSR) и в браузере (навигация), не имеет доступа к locals/cookies/БД. +page.server.ts работает только на сервере, имеет доступ к locals, cookies, секретам и может экспортировать Form Actions.
load в +page.ts vs +page.server.ts
Оба файла экспортируют функцию load, которая возвращает данные для +page.svelte через проп data. Ключевое различие — где и когда они выполняются.
+page.ts — универсальный загрузчик
- Выполняется на сервере при SSR (первый запрос) и в браузере при клиентской навигации.
- Имеет доступ к
fetch(уже настроенному SvelteKit для правильной обработки cookie/credentials),params,url,route,data(от layout). - НЕ имеет доступа к
locals,cookies, переменным из$env/static/private. - Подходит для запросов к публичным API без авторизации.
// src/routes/products/+page.ts
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ fetch, url }) => {
const page = url.searchParams.get('page') ?? '1';
// fetch здесь — это SvelteKit-обёртка, работающая и на сервере и в браузере
const res = await fetch(`/api/products?page=${page}`);
const products = await res.json();
return { products };
};
+page.server.ts — серверный загрузчик
- Выполняется только на сервере — при SSR и при каждой клиентской навигации (через внутренний fetch к серверу).
- Имеет доступ к
locals(пользователь изhandle()),cookies,platform(Cloudflare Workers env), секретным переменным окружения. - Может напрямую обращаться к БД, файловой системе, внутренним сервисам.
- Дополнительно экспортирует
actionsдля обработки форм.
// src/routes/account/+page.server.ts
import { redirect, error } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ locals, cookies }) => {
// locals.user — установлен в hooks.server.ts
if (!locals.user) {
throw redirect(303, '/login');
}
// Прямой запрос к БД — возможен только здесь
const orders = await db.orders.findByUser(locals.user.id);
const sessionInfo = cookies.get('session');
return { user: locals.user, orders };
};
Совместное использование
Оба файла могут существовать одновременно. Данные мёржатся: +page.ts получает data из серверного загрузчика через параметр parent().
// +page.server.ts
export const load = async ({ locals }) => {
return { user: locals.user }; // Только сервер
};
// +page.ts
export const load = async ({ fetch, parent }) => {
const { user } = await parent(); // Данные из server load
const posts = await fetch('/api/posts').then(r => r.json());
return { posts }; // Мёржится с { user }
};
Таблица сравнения
- Где выполняется: .ts — сервер + браузер; .server.ts — только сервер
- locals/cookies: .ts — нет; .server.ts — да
- Прямой доступ к БД: .ts — нет; .server.ts — да
- fetch к публичным API: .ts — да; .server.ts — да
- Form actions: .ts — нет; .server.ts — да
- Повторный вызов при навигации: .ts — в браузере; .server.ts — через сервер
Подводные камни
- Если используется только
+page.tsи в нём делается запрос к защищённому API, при клиентской навигации cookie может не передаться корректно — используйте+page.server.tsдля чувствительных данных. parent()в+page.tsждёт завершения+page.server.tsи layout загрузчиков — это блокирует параллелизм; не вызывайтеparent()если данные не нужны немедленно.- При наличии обоих файлов TypeScript тип
PageDataобъединяет оба возвращаемых значения — убедитесь, что нет конфликтующих ключей. - В
+page.server.tsданные сериализуются из сервера в браузер через devalue — Map, Set, Date поддерживаются, но кастомные классы — нет. +page.tsсexport const ssr = falseбудет выполняться только в браузере — это полезно для страниц с клиентским состоянием, но убивает SEO.- Функция
fetchвнутри+page.tsпри SSR делает внутренний запрос к серверу SvelteKit — это накладные расходы; для серверных данных предпочитайте+page.server.tsс прямым вызовом.
Common mistakes
- Путать load functions с похожим API из соседнего фреймворка.
- Не объяснять, где код выполняется: сервер, клиент, build step или runtime.
- Игнорировать влияние на hydration, cache, bundle size или безопасность.
What the interviewer is testing
- Точно объясняет назначение механизма «load functions».
- Показывает корректный минимальный пример без выдуманных API.
- Называет ограничения, failure modes и production-компромиссы.