Svelte의 풀스택 진화,
SvelteKit
Svelte 컴포넌트 위에 라우팅, 서버 사이드 렌더링, API 라우트, 어댑터 기반 배포까지 더한 풀스택 프레임워크. Next.js가 React에게 하는 역할을 SvelteKit이 Svelte에게 한다.
Svelte 단독으로는 컴포넌트를 만들 수 있지만, 실제 웹 앱을 만들려면 라우팅과 서버 렌더링이 필요하다. SvelteKit은 그 빈 자리를 채우며 Svelte를 완전한 풀스택 솔루션으로 만든다.
파일 기반 라우팅
SvelteKit은 파일 시스템 기반 라우팅을 사용한다. src/routes 폴더 구조가 곧 URL 구조가 된다. 특별한 라우터 설정 파일 없이 폴더와 파일만으로 라우팅을 정의한다.
특별한 파일들
SvelteKit의 라우팅은 몇 가지 규약 파일로 동작한다. 파일 이름이 곧 역할을 결정한다.
+page.svelte
라우트의 UI 컴포넌트. 해당 URL로 접근했을 때 렌더링되는 페이지다.
+page.server.js
서버에서만 실행되는 load 함수와 actions(폼 처리)를 정의한다.
+layout.svelte
해당 라우트와 하위 라우트에 공통으로 적용되는 레이아웃 컴포넌트.
+server.js
GET, POST, PUT, DELETE 핸들러를 정의하는 API 엔드포인트 파일.
데이터 로딩: load 함수
SvelteKit의 핵심 패턴은 load 함수다. 페이지가 렌더링되기 전에 필요한 데이터를 서버에서 준비하고, 자동으로 페이지 컴포넌트의 data prop으로 전달한다.
// src/routes/blog/[slug]/+page.server.js
import { error } from '@sveltejs/kit';
import { db } from '$lib/db';
export async function load({ params }) {
const post = await db.post.findUnique({
where: { slug: params.slug }
});
if (!post) {
error(404, '포스트를 찾을 수 없습니다');
}
return { post };
}
<!-- src/routes/blog/[slug]/+page.svelte -->
<script>
let { data } = $props(); // load()의 반환값
</script>
<h1>{data.post.title}</h1>
<p>{data.post.content}</p>
서버에서 직접 DB 접근: +page.server.js의 load 함수는 서버에서만 실행된다. 데이터베이스, 환경 변수, 파일 시스템에 직접 접근할 수 있다. 별도의 API 라우트를 만들 필요 없이 페이지 데이터를 서버에서 곧바로 가져온다.
API 라우트
+server.js 파일로 REST API 엔드포인트를 만들 수 있다. SvelteKit은 백엔드 서버 없이 프론트엔드 프레임워크 안에서 API를 완성할 수 있게 해준다.
// src/routes/api/users/+server.js
import { json } from '@sveltejs/kit';
import { db } from '$lib/db';
export async function GET() {
const users = await db.user.findMany();
return json(users);
}
export async function POST({ request }) {
const body = await request.json();
const user = await db.user.create({ data: body });
return json(user, { status: 201 });
}
Form Actions: 서버 폼 처리
SvelteKit의 독특한 기능 중 하나가 Form Actions다. JavaScript 없이도 작동하는 점진적 향상(Progressive Enhancement) 방식의 폼 처리를 지원한다.
// +page.server.js
export const actions = {
login: async ({ request, cookies }) => {
const data = await request.formData();
const email = data.get('email');
const password = data.get('password');
const user = await authenticate(email, password);
if (!user) {
return { error: '이메일 또는 비밀번호가 올바르지 않습니다' };
}
cookies.set('session', user.token, { path: '/' });
}
};
<!-- +page.svelte -->
<script>
let { form } = $props();
</script>
<form method="POST" action="?/login">
{#if form?.error}
<p class="error">{form.error}</p>
{/if}
<input name="email" type="email" />
<input name="password" type="password" />
<button>로그인</button>
</form>
어댑터: 어디서나 배포
SvelteKit의 강점 중 하나는 어댑터(Adapter) 시스템이다. 빌드 결과물을 다양한 플랫폼에 맞게 변환한다.
adapter-node
Node.js 서버로 실행. Express나 Docker 환경에서 직접 구동할 수 있다.
adapter-static
완전한 정적 사이트(SSG)로 생성. GitHub Pages, Netlify, S3에 파일 배포.
adapter-vercel
Vercel Edge/Serverless 함수로 자동 변환. 설정 없이 최적화 배포.
adapter-cloudflare
Cloudflare Workers로 배포. 전 세계 엣지 네트워크에서 실행.
레이아웃 시스템
+layout.svelte를 사용하면 라우트 그룹에 공통 레이아웃을 적용할 수 있다. 중첩 레이아웃도 지원하며, 레이아웃도 +layout.server.js로 서버 데이터를 가져올 수 있다.
<!-- src/routes/+layout.svelte (루트 레이아웃) -->
<script>
let { children, data } = $props();
</script>
<nav>
<a href="/">홈</a>
<a href="/blog">블로그</a>
{#if data.user}
<span>{data.user.name}</span>
{/if}
</nav>
<!-- 각 페이지가 여기에 렌더링됨 -->
{@render children()}
SvelteKit은 Svelte의 단순함과 성능을 그대로 유지하면서 실제 웹 앱에 필요한 모든 것을 제공한다. Next.js에 비해 학습 곡선이 낮고, 번들 크기가 작으며, 개발 경험이 직관적이다. Svelte를 선택했다면 SvelteKit은 자연스러운 다음 단계다.
댓글