Перейти к содержимому

21. SvelteKit: Введение

Привет! 👋 Если Svelte — это двигатель, то SvelteKit — это полноценный автомобиль 🚗. Двигатель сам по себе не едет — нужны ещё колёса, руль, коробка передач. SvelteKit добавляет всё это: роутинг, SSR, API, деплой, и многое другое.

Думай о SvelteKit как о Next.js, но для Svelte. Только честнее по философии и быстрее по умолчанию.


Svelte сам по себе — это только библиотека для создания компонентов. Когда ты пишешь .svelte файлы, ты получаешь компилируемые компоненты. Но для полноценного веб-приложения нужно гораздо больше:

Svelte (только компоненты):
✅ Реактивные компоненты
✅ Компиляция в чистый JS
❌ Роутинг
❌ SSR / SSG
❌ API routes
❌ Оптимизация кода
❌ Адаптеры для деплоя
SvelteKit (полный фреймворк):
✅ Всё из Svelte +
✅ Файловый роутинг (как Next.js App Router)
✅ SSR + SSG + SPA — всё в одном
✅ API routes (+server.ts)
✅ Загрузка данных (load functions)
✅ Form Actions (серверные формы)
✅ Адаптеры для любой платформы
✅ Hot Module Replacement через Vite
✅ TypeScript из коробки

my-sveltekit-app/
├── src/
│ ├── routes/ ← ВСЯ логика роутинга здесь
│ │ ├── +page.svelte ← Главная страница (/)
│ │ ├── +layout.svelte ← Общий layout для всех страниц
│ │ ├── +error.svelte ← Страница ошибки
│ │ ├── about/
│ │ │ └── +page.svelte ← Страница /about
│ │ ├── blog/
│ │ │ ├── +page.svelte ← Список постов /blog
│ │ │ ├── +page.ts ← Загрузка данных для списка
│ │ │ └── [slug]/
│ │ │ ├── +page.svelte ← Пост /blog/my-post
│ │ │ └── +page.server.ts ← Серверная загрузка
│ │ └── api/
│ │ └── users/
│ │ └── +server.ts ← API endpoint /api/users
│ ├── lib/ ← Переиспользуемый код ($lib alias)
│ │ ├── components/
│ │ ├── utils/
│ │ └── server/ ← Серверный код (только сервер!)
│ ├── app.html ← HTML шаблон
│ ├── app.d.ts ← TypeScript декларации
│ └── hooks.server.ts ← Серверные хуки
├── static/ ← Статические файлы (favicon, robots.txt)
├── svelte.config.js ← Конфигурация SvelteKit
├── vite.config.ts ← Конфигурация Vite
└── package.json

svelte.config.js
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Препроцессоры — для TypeScript, SCSS, etc.
preprocess: vitePreprocess(),
kit: {
// Адаптер определяет, куда и как деплоить
adapter: adapter(),
// Алиас для src/lib/
alias: {
$lib: 'src/lib',
$components: 'src/lib/components',
$utils: 'src/lib/utils',
},
// Предрендеринг по умолчанию
prerender: {
handleHttpError: 'warn',
},
// CSP заголовки
csp: {
directives: {
'default-src': ['self'],
},
},
},
};
export default config;
vite.config.ts
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit()],
// Дополнительные настройки Vite:
server: {
port: 3000,
},
test: {
include: ['src/**/*.{test,spec}.{js,ts}'],
},
});

Адаптер — это плагин, который “упаковывает” твоё SvelteKit приложение для конкретной платформы. Это главное конкурентное преимущество SvelteKit перед Next.js — ты не привязан к одной облачной платформе.

Адаптер Платформа Особенности
────────────────────────────────────────────────────────────
adapter-auto Автодетект Vercel/Netlify/Cloudflare/Node
adapter-node Node.js сервер PM2, Docker, VPS
adapter-vercel Vercel Edge Functions, ISR
adapter-netlify Netlify Edge Functions
adapter-cloudflare Cloudflare Workers Глобально распределённый
adapter-static Чистый HTML/CSS/JS GitHub Pages, S3

Настройка адаптеров:

// Для Node.js:
import adapter from '@sveltejs/adapter-node';
const config = {
kit: {
adapter: adapter({
out: 'build', // Выходная папка
precompress: true, // Gzip/Brotli сжатие
envPrefix: 'MY_APP_', // Префикс переменных окружения
}),
},
};
// Для Vercel:
import adapter from '@sveltejs/adapter-vercel';
const config = {
kit: {
adapter: adapter({
runtime: 'nodejs20.x',
regions: ['fra1'], // Регион Frankfurt
// Или Edge Functions:
// runtime: 'edge',
}),
},
};
// Для статического сайта:
import adapter from '@sveltejs/adapter-static';
const config = {
kit: {
adapter: adapter({
pages: 'build', // Куда положить HTML
assets: 'build', // Куда положить ассеты
fallback: '404.html', // Для SPA fallback
precompress: false,
}),
// Для статики нужно предрендерить все страницы:
prerender: {
entries: ['*'],
},
},
};

src/lib/ — это специальная директория, которую SvelteKit добавляет в $lib алиас. Это позволяет избежать ужасных относительных импортов типа ../../../../utils.

// ❌ Без $lib — кошмар относительных путей:
import { Button } from '../../../components/ui/Button.svelte';
import { formatDate } from '../../utils/date';
import { db } from '../../lib/server/database';
// ✅ С $lib — чисто и понятно:
import { Button } from '$lib/components/ui/Button.svelte';
import { formatDate } from '$lib/utils/date';
import { db } from '$lib/server/database'; // Только на сервере!

Структура $lib:

// src/lib/index.ts — публичный API библиотеки
export { default as Button } from './components/Button.svelte';
export { default as Modal } from './components/Modal.svelte';
export { formatDate, formatCurrency } from './utils/formatting';
export type { User, Post, Comment } from './types';
// src/lib/server/database.ts — ТОЛЬКО серверный код
// Файлы в src/lib/server/ недоступны на клиенте
import { PrismaClient } from '@prisma/client';
export const db = new PrismaClient();
// src/lib/utils/formatting.ts
export function formatDate(date: Date): string {
return new Intl.DateTimeFormat('ru-RU', {
day: 'numeric',
month: 'long',
year: 'numeric',
}).format(date);
}
export function formatCurrency(amount: number, currency = 'RUB'): string {
return new Intl.NumberFormat('ru-RU', {
style: 'currency',
currency,
}).format(amount);
}

ХарактеристикаSvelteKitNext.js
ЯзыкSvelte + TypeScriptReact + TypeScript
РоутингФайловый (src/routes/)Файловый (app/)
SSR✅ Из коробки✅ Из коробки
SSG✅ adapter-static✅ generateStaticParams
API Routes+server.tsroute.ts
Загрузка данныхload() функцииServer Components + fetch
ФормыForm ActionsServer Actions
Bundle size~10-30KB~70-100KB
Компилятор✅ Svelte компилятор❌ Нет компилятора (transpiler)
Virtual DOM❌ Не нужен✅ React VDOM
TypeScript DX⭐⭐⭐⭐⭐⭐⭐⭐⭐
ЭкосистемаРастущаяОгромная
РаботаМеньшеМного
Vercel поддержка✅ Хорошая✅ Родная
Cloudflare Workers✅ Отличная⚠️ Ограниченная
Кривая обученияПологаяКрутая

Код для сравнения — загрузка данных:

src/routes/blog/+page.server.ts
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ fetch }) => {
const posts = await fetch('/api/posts').then(r => r.json());
return { posts };
};
src/routes/blog/+page.svelte
<script lang="ts">
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
</script>
{#each data.posts as post}
<article>{post.title}</article>
{/each}
app/blog/page.tsx
async function getPosts() {
return fetch('/api/posts').then(r => r.json());
}
export default async function BlogPage() {
const posts = await getPosts();
return (
<div>
{posts.map((post: any) => (
<article key={post.id}>{post.title}</article>
))}
</div>
);
}

Используй Plain Svelte если:
✓ Встраиваешь компоненты в другой проект (Django, Rails, etc.)
✓ Создаёшь виджет или библиотеку компонентов
✓ Есть свой сборщик и роутер
✓ Нужна максимальная свобода в конфигурации
Используй SvelteKit если:
✓ Создаёшь полноценный веб-сайт или приложение
✓ Нужен SSR для SEO
✓ Нужны API routes
✓ Планируешь деплоить на разные платформы
✓ Нужны быстрая навигация и prefetching
✓ Нужна серверная обработка форм

🌐 Рендеринг в SvelteKit: SSR, SSG, SPA — всё в одном

Заголовок раздела «🌐 Рендеринг в SvelteKit: SSR, SSG, SPA — всё в одном»
src/routes/+page.svelte
<script lang="ts">
// Эта страница рендерится на сервере при каждом запросе (SSR)
</script>
src/routes/+page.ts
// Отключаем SSR — клиентский SPA режим:
export const ssr = false;
// Включаем предрендеринг — статический сайт:
export const prerender = true;
// Или per-page конфигурация:
export const config = {
isr: {
expiration: 60, // Incremental Static Regeneration (Vercel)
},
};
// src/routes/api/users/+server.ts — API route не рендерится
// Всегда серверный, всегда динамический
export async function GET() {
return new Response(JSON.stringify({ users: [] }));
}

Окно терминала
npm create svelte@latest my-app
# Варианты шаблонов:
# - SvelteKit demo app (с примерами)
# - Skeleton project (пустой)
# - Library project (для публикации npm пакета)
cd my-app
npm install
npm run dev
Окно терминала
# Добавляем зависимости:
npm install -D @sveltejs/adapter-node # Для Node.js
npm install -D @sveltejs/adapter-vercel # Для Vercel
npm install -D @sveltejs/adapter-static # Для статики
npm install drizzle-orm # ORM
npm install @auth/sveltekit # Auth.js

// src/app.d.ts — глобальные типы для SvelteKit
declare global {
namespace App {
// Тип для event.locals — данные доступные в хуках и load функциях
interface Locals {
user: {
id: string;
email: string;
role: 'admin' | 'user';
} | null;
}
// Тип для метаданных страниц
interface PageData {
// Глобальные данные доступные на всех страницах
theme?: 'light' | 'dark';
}
// Тип для ошибок
interface Error {
message: string;
code?: string;
}
// Тип для переменных окружения (platform-specific)
interface Platform {
env: {
DATABASE_URL: string;
};
}
}
}
export {};