What SvelteKit Does
- File-Based Routing: Routes defined by file structure in
src/routes - SSR/SSG/CSR: Server-side rendering, static generation, or client-only rendering
- Server Actions: Form submissions handled on the server with progressive enhancement
- Load Functions: Type-safe server data loading for pages
- Layouts: Nested layouts with shared data
- API Routes: RESTful endpoints as file-based routes
- Adapters: Deploy to Vercel, Netlify, Cloudflare, Node, static hosting
- Hot Module Replacement: Instant updates via Vite
- TypeScript: First-class TypeScript support
- Link Prefetching: Automatic prefetching on hover
Project Structure
my-app/
├── src/
│ ├── routes/ ← File-based routing
│ │ ├── +page.svelte ← Home page
│ │ ├── +layout.svelte ← Root layout
│ │ ├── about/
│ │ │ └── +page.svelte
│ │ └── blog/
│ │ ├── +page.svelte ← Blog list
│ │ ├── +page.server.ts ← Server data loader
│ │ └── [slug]/
│ │ ├── +page.svelte
│ │ └── +page.server.ts
│ ├── lib/ ← Shared utilities
│ │ ├── components/
│ │ └── db.ts
│ ├── app.html
│ └── hooks.server.ts ← Server hooks (auth, etc.)
├── svelte.config.js
└── vite.config.jsBasic Components
Simple Page
<!-- src/routes/+page.svelte -->
<script lang="ts">
let count = 0;
function increment() {
count++;
}
</script>
<h1>Welcome to SvelteKit!</h1>
<button on:click={increment}>
Clicked {count} {count === 1 ? 'time' : 'times'}
</button>
<style>
h1 {
color: #ff3e00;
}
</style>Reactive Statements
<script lang="ts">
let firstName = 'John';
let lastName = 'Doe';
// Reactive computed value
$: fullName = `${firstName} ${lastName}`;
// Reactive statement - runs on dependency change
$: console.log(`Name changed to: ${fullName}`);
// Can have conditions
$: if (fullName.length > 20) {
console.warn('Name is very long!');
}
</script>
<input bind:value={firstName} />
<input bind:value={lastName} />
<p>Hello, {fullName}!</p>Data Loading
Server Load Function
// src/routes/blog/+page.server.ts
import type { PageServerLoad } from './$types';
import { db } from '$lib/db';
export const load: PageServerLoad = async () => {
const posts = await db.post.findMany({
orderBy: { createdAt: 'desc' },
take: 10,
});
return { posts };
};<!-- src/routes/blog/+page.svelte -->
<script lang="ts">
import type { PageData } from './$types';
export let data: PageData;
// data.posts is fully typed!
</script>
<h1>Blog Posts</h1>
<ul>
{#each data.posts as post}
<li>
<a href="/blog/{post.slug}">{post.title}</a>
</li>
{/each}
</ul>Dynamic Route
// src/routes/blog/[slug]/+page.server.ts
import type { PageServerLoad } from './$types';
import { error } from '@sveltejs/kit';
export const load: PageServerLoad = async ({ params }) => {
const post = await db.post.findUnique({
where: { slug: params.slug },
});
if (!post) {
throw error(404, 'Post not found');
}
return { post };
};Server Actions (Forms)
// src/routes/login/+page.server.ts
import type { Actions } from './$types';
import { fail, redirect } from '@sveltejs/kit';
export const actions: Actions = {
default: async ({ request, cookies }) => {
const data = await request.formData();
const email = data.get('email');
const password = data.get('password');
if (!email || !password) {
return fail(400, { email, missing: true });
}
const user = await authenticate(email, password);
if (!user) {
return fail(401, { email, incorrect: true });
}
cookies.set('session', user.sessionId, { path: '/' });
throw redirect(303, '/dashboard');
},
};<!-- src/routes/login/+page.svelte -->
<script lang="ts">
import { enhance } from '$app/forms';
import type { ActionData } from './$types';
export let form: ActionData;
</script>
<!-- Works without JavaScript! Progressive enhancement -->
<form method="POST" use:enhance>
<input name="email" value={form?.email ?? ''} />
{#if form?.missing}<p>Email required</p>{/if}
<input name="password" type="password" />
{#if form?.incorrect}<p>Invalid credentials</p>{/if}
<button>Log in</button>
</form>API Routes
// src/routes/api/users/+server.ts
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
export const GET: RequestHandler = async ({ url }) => {
const limit = Number(url.searchParams.get('limit') ?? '10');
const users = await db.user.findMany({ take: limit });
return json(users);
};
export const POST: RequestHandler = async ({ request }) => {
const body = await request.json();
const user = await db.user.create({ data: body });
return json(user, { status: 201 });
};Layouts
<!-- src/routes/+layout.svelte -->
<script>
import '../app.css';
import Header from '$lib/components/Header.svelte';
</script>
<Header />
<main>
<slot /> <!-- Child pages render here -->
</main>
<footer>© 2024 My Site</footer><!-- src/routes/blog/+layout.svelte - nested layout -->
<div class="blog-layout">
<aside>Blog sidebar</aside>
<article>
<slot />
</article>
</div>Deployment Adapters
// svelte.config.js - choose adapter
import adapter from '@sveltejs/adapter-auto';
// Or specific:
// import adapter from '@sveltejs/adapter-vercel';
// import adapter from '@sveltejs/adapter-netlify';
// import adapter from '@sveltejs/adapter-cloudflare';
// import adapter from '@sveltejs/adapter-node';
// import adapter from '@sveltejs/adapter-static';
export default {
kit: {
adapter: adapter(),
},
};Why Svelte?
Compiler-Based
Unlike React (virtual DOM) or Solid (signals), Svelte is a compiler. Components are compiled to highly optimized vanilla JavaScript at build time — no runtime framework needed.
Your Component (5KB)
→ Svelte Compiler
→ Optimized JS (2KB, no framework)Svelte 5 (Runes)
<script>
// New reactive primitives in Svelte 5
let count = $state(0);
let doubled = $derived(count * 2);
$effect(() => {
console.log('count changed:', count);
});
</script>
<button onclick={() => count++}>
{count} (doubled: {doubled})
</button>SvelteKit vs Alternatives
| Feature | SvelteKit | Next.js | Nuxt | Remix |
|---|---|---|---|---|
| Framework | Svelte (compiler) | React | Vue | React |
| Bundle size | Smallest | Medium | Medium | Medium |
| Routing | File-based | File-based (App Router) | File-based | File-based |
| Server actions | Yes | Yes | Server handlers | Yes |
| SSR/SSG/CSR | All three | All three | All three | Server-focused |
| Dev speed (Vite) | Yes | Turbopack | Vite | Vite |
| Learning curve | Easy | Medium | Easy | Medium |
| Deployment | All major | Vercel optimized | All major | All major |
常见问题
Q: Svelte 和 React 哪个更好? A: Svelte 更简洁(更少的样板代码)、性能更好(编译后无运行时)、包体积更小。React 生态更大、人才更多、大型应用模式更成熟。对于新项目,Svelte 开发体验更好;对于企业级,React 更稳妥。
Q: Svelte 5 的 runes 是什么?
A: Svelte 5 引入的新反应式原语($state、$derived、$effect),替换之前的 let + $: 语法。新 API 更明确,适合大型项目,与旧语法保持兼容。
Q: 适合什么项目? A: 任何 Web 项目:内容网站(SSG)、SaaS 应用(SSR)、管理后台(CSR)。SvelteKit 灵活性高,可以在同一应用中混合不同渲染模式。特别适合性能敏感和开发者体验优先的项目。
来源与致谢
- GitHub: sveltejs/kit — 20.4K+ ⭐ | MIT
- 官网: kit.svelte.dev