21. SvelteKit: Введение
🚀 SvelteKit: Svelte на максималках
Заголовок раздела «🚀 SvelteKit: Svelte на максималках»Привет! 👋 Если Svelte — это двигатель, то SvelteKit — это полноценный автомобиль 🚗. Двигатель сам по себе не едет — нужны ещё колёса, руль, коробка передач. SvelteKit добавляет всё это: роутинг, SSR, API, деплой, и многое другое.
Думай о SvelteKit как о Next.js, но для Svelte. Только честнее по философии и быстрее по умолчанию.
🗺️ Что SvelteKit добавляет к Svelte
Заголовок раздела «🗺️ Что SvelteKit добавляет к 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 из коробки📁 Структура проекта SvelteKit
Заголовок раздела «📁 Структура проекта SvelteKit»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: сердце конфигурации
Заголовок раздела «⚙️ 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;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/Nodeadapter-node Node.js сервер PM2, Docker, VPSadapter-vercel Vercel Edge Functions, ISRadapter-netlify Netlify Edge Functionsadapter-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: ['*'], }, },};📦 $lib алиас: переиспользуемый код
Заголовок раздела «📦 $lib алиас: переиспользуемый код»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.tsexport 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);}🆚 SvelteKit vs Next.js: подробное сравнение
Заголовок раздела «🆚 SvelteKit vs Next.js: подробное сравнение»| Характеристика | SvelteKit | Next.js |
|---|---|---|
| Язык | Svelte + TypeScript | React + TypeScript |
| Роутинг | Файловый (src/routes/) | Файловый (app/) |
| SSR | ✅ Из коробки | ✅ Из коробки |
| SSG | ✅ adapter-static | ✅ generateStaticParams |
| API Routes | +server.ts | route.ts |
| Загрузка данных | load() функции | Server Components + fetch |
| Формы | Form Actions | Server Actions |
| Bundle size | ~10-30KB | ~70-100KB |
| Компилятор | ✅ Svelte компилятор | ❌ Нет компилятора (transpiler) |
| Virtual DOM | ❌ Не нужен | ✅ React VDOM |
| TypeScript DX | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Экосистема | Растущая | Огромная |
| Работа | Меньше | Много |
| Vercel поддержка | ✅ Хорошая | ✅ Родная |
| Cloudflare Workers | ✅ Отличная | ⚠️ Ограниченная |
| Кривая обучения | Пологая | Крутая |
Код для сравнения — загрузка данных:
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ fetch }) => { const posts = await fetch('/api/posts').then(r => r.json()); return { posts };};<script lang="ts"> import type { PageData } from './$types'; let { data }: { data: PageData } = $props();</script>
{#each data.posts as post} <article>{post.title}</article>{/each}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> );}🤔 Когда выбирать SvelteKit vs Plain Svelte
Заголовок раздела «🤔 Когда выбирать SvelteKit vs Plain Svelte»Используй Plain Svelte если: ✓ Встраиваешь компоненты в другой проект (Django, Rails, etc.) ✓ Создаёшь виджет или библиотеку компонентов ✓ Есть свой сборщик и роутер ✓ Нужна максимальная свобода в конфигурации
Используй SvelteKit если: ✓ Создаёшь полноценный веб-сайт или приложение ✓ Нужен SSR для SEO ✓ Нужны API routes ✓ Планируешь деплоить на разные платформы ✓ Нужны быстрая навигация и prefetching ✓ Нужна серверная обработка форм🌐 Рендеринг в SvelteKit: SSR, SSG, SPA — всё в одном
Заголовок раздела «🌐 Рендеринг в SvelteKit: SSR, SSG, SPA — всё в одном»<script lang="ts"> // Эта страница рендерится на сервере при каждом запросе (SSR)</script>// Отключаем 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: [] }));}🎯 Создание нового SvelteKit проекта
Заголовок раздела «🎯 Создание нового SvelteKit проекта»npm create svelte@latest my-app
# Варианты шаблонов:# - SvelteKit demo app (с примерами)# - Skeleton project (пустой)# - Library project (для публикации npm пакета)
cd my-appnpm installnpm run dev# Добавляем зависимости:npm install -D @sveltejs/adapter-node # Для Node.jsnpm install -D @sveltejs/adapter-vercel # Для Vercelnpm install -D @sveltejs/adapter-static # Для статикиnpm install drizzle-orm # ORMnpm install @auth/sveltekit # Auth.js📋 app.d.ts: TypeScript декларации
Заголовок раздела «📋 app.d.ts: TypeScript декларации»// src/app.d.ts — глобальные типы для SvelteKitdeclare 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 {};