SvelteKit 시작하기 - 현대적인 웹 프레임워크 완벽 가이드
SvelteKit의 기초부터 실전 배포까지 완벽하게 마스터하세요. 프로젝트 설정, 라우팅, 데이터 로딩, API 엔드포인트 구축, SSR/SSG 최적화 기법을 실습 중심으로 설명합니다. 초보자도 따라 할 수 있는 단계별 튜토리얼로 현대적인 웹 애플리케이션 개발을 시작해보세요.
📋 핵심 내용 요약
- 현대적 프레임워크: Svelte 기반의 공식 풀스택 애플리케이션 프레임워크
- 파일 기반 라우팅: 직관적인 디렉토리 구조로 라우트 자동 생성
- 뛰어난 성능: 가상 DOM 없이 빠른 실행 속도와 작은 번들 크기
- 유연한 배포: SPA, MPA, SSR, SSG 모두 지원 + 다양한 어댑터
- 개발 경험: 간결한 코드 + TypeScript 완벽 지원 + 핫 모듈 리로딩
🤖 AI 요약
SvelteKit은 Svelte 팀이 만든 차세대 웹 애플리케이션 프레임워크로, React의 Next.js나 Vue의 Nuxt와 유사하지만 더 나은 성능과 개발 경험을 제공합니다.
왜 SvelteKit인가? 가상 DOM을 사용하지 않아 더 빠른 실행 속도와 작은 번들 크기를 자랑합니다. 컴파일 타임에 최적화된 순수 JavaScript로 변환되므로 런타임 오버헤드가 거의 없습니다. 코드도 훨씬 간결하고 읽기 쉽습니다.
파일 기반 라우팅: src/routes/ 디렉토리 구조가 곧 URL 구조입니다. +page.svelte로 페이지를, +layout.svelte로 공통 레이아웃을, +server.ts로 API 엔드포인트를 만들 수 있습니다. 대괄호 [slug]를 사용하면 동적 라우트도 쉽게 구현됩니다.
데이터 로딩: +page.ts(Universal Load)는 클라이언트/서버 양쪽에서, +page.server.ts(Server Load)는 서버에서만 실행됩니다. 민감한 데이터는 Server Load에서 처리하여 보안을 유지할 수 있습니다.
유연한 배포: 다양한 어댑터로 어디든 배포 가능합니다 - Vercel, Netlify, Cloudflare Pages, Node.js 서버, 또는 완전한 정적 사이트로 빌드할 수 있습니다. SPA, MPA, SSR, SSG 모두 지원하므로 프로젝트 요구사항에 맞게 선택할 수 있습니다.
개발 경험: TypeScript 완벽 지원, 핫 모듈 리로딩, Tailwind CSS 통합, 그리고 Vite 기반의 빠른 개발 서버까지 - 모든 것이 현대적인 개발 경험을 위해 최적화되어 있습니다.
SvelteKit은 현대적인 웹 애플리케이션을 구축하기 위한 강력한 프레임워크입니다. 이 글에서는 SvelteKit의 기초부터 실전 활용까지 단계별로 알아보겠습니다.
SvelteKit이란?
SvelteKit은 Svelte 팀이 만든 공식 애플리케이션 프레임워크로, 다음과 같은 기능을 제공합니다:
- 📁 파일 기반 라우팅: 직관적인 디렉토리 구조로 라우트 관리
- ⚡ 서버 사이드 렌더링: 빠른 초기 페이지 로딩
- 🏗️ 정적 사이트 생성: 어디든 배포 가능
- 🔌 API 라우트: 프론트엔드와 백엔드를 함께 구축
- 🔥 핫 모듈 리로딩: 개발 중 즉각적인 피드백
왜 SvelteKit인가?
다른 프레임워크와 비교했을 때 SvelteKit의 장점:
1. 성능
- 가상 DOM이 없어 빠른 실행 속도
- 최소한의 JavaScript 번들 크기
- 최적화된 빌드 출력
2. 개발 경험
- 간결하고 읽기 쉬운 코드
- 반응성이 기본으로 내장
- TypeScript 완벽 지원
3. 유연성
- SPA, MPA, SSR, SSG 모두 지원
- 다양한 어댑터로 어디든 배포
- 점진적 개선 가능
사전 준비사항
시작하기 전에 다음을 준비하세요:
- Node.js (버전 18 이상)
- 코드 에디터 (VS Code 추천)
- 기본 지식: JavaScript, HTML, CSS
새 프로젝트 만들기
SvelteKit 프로젝트를 생성하는 방법:
# 프로젝트 생성
npm create svelte@latest my-app
# 프로젝트 디렉토리로 이동
cd my-app
# 의존성 설치
npm install
# 개발 서버 시작
npm run dev 설치 과정에서 다음을 선택하게 됩니다:
- 프로젝트 템플릿: Skeleton project (기본) 또는 SvelteKit demo app
- TypeScript 사용 여부: Yes (강력 추천!)
- ESLint, Prettier: Yes (코드 품질 도구)
- Playwright: Yes (E2E 테스팅)
- Vitest: Yes (단위 테스트)
프로젝트 구조
생성된 프로젝트의 구조를 이해해봅시다:
my-app/
├── src/
│ ├── routes/ # 페이지 및 라우트
│ │ ├── +page.svelte # 홈페이지
│ │ ├── +layout.svelte # 공통 레이아웃
│ │ └── +error.svelte # 에러 페이지
│ ├── lib/ # 공유 컴포넌트 및 유틸
│ │ ├── components/ # UI 컴포넌트
│ │ └── utils/ # 헬퍼 함수
│ └── app.html # HTML 템플릿
├── static/ # 정적 파일 (이미지, favicon 등)
├── svelte.config.js # SvelteKit 설정
├── vite.config.ts # Vite 설정
└── package.json # 프로젝트 의존성 주요 디렉토리 설명
src/routes/
- 모든 페이지와 API 엔드포인트가 위치
- 디렉토리 구조가 곧 URL 구조
src/lib/
- 재사용 가능한 컴포넌트와 유틸리티
$lib로 간편하게 임포트 가능
static/
- 이미지, 폰트, favicon 등 정적 파일
- 빌드 시 그대로 복사됨
라우팅 시스템
SvelteKit의 파일 기반 라우팅은 매우 직관적입니다.
기본 라우트
src/routes/+page.svelte → /
src/routes/about/+page.svelte → /about
src/routes/blog/+page.svelte → /blog
src/routes/contact/+page.svelte → /contact 동적 라우트
대괄호를 사용해 동적 파라미터를 만들 수 있습니다:
// src/routes/blog/[slug]/+page.ts
import { error } from '@sveltejs/kit';
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ params }) => {
const post = await getPost(params.slug);
if (!post) {
throw error(404, 'Post not found');
}
return { post };
}; <!-- src/routes/blog/[slug]/+page.svelte -->
<script lang="ts">export let data;
</script>
<article>
<h1>{data.post.title}</h1>
<time>{data.post.date}</time>
<div class="prose">
{@html data.post.content}
</div>
</article>
<style>
article {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
}
</style> 중첩 라우트와 레이아웃
<!-- src/routes/blog/+layout.svelte -->
<script lang="ts">import BlogSidebar from "$lib/components/BlogSidebar.svelte";
</script>
<div class="blog-layout">
<aside>
<BlogSidebar />
</aside>
<main>
<slot /> <!-- 자식 페이지가 여기에 렌더링 -->
</main>
</div>
<style>
.blog-layout {
display: grid;
grid-template-columns: 250px 1fr;
gap: 2rem;
}
</style> 데이터 로딩
SvelteKit에서 데이터를 로드하는 두 가지 방법:
1. Universal Load (+page.ts)
클라이언트와 서버 모두에서 실행됩니다:
// src/routes/posts/+page.ts
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ fetch }) => {
const response = await fetch('https://api.example.com/posts');
const posts = await response.json();
return {
posts
};
}; 2. Server Load (+page.server.ts)
서버에서만 실행되며, 민감한 데이터 처리 가능:
// src/routes/dashboard/+page.server.ts
import { redirect } from '@sveltejs/kit';
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async ({ locals, cookies }) => {
// 인증 확인
if (!locals.user) {
throw redirect(307, '/login');
}
// 데이터베이스 조회 (서버에서만 실행)
const userData = await db.getUserData(locals.user.id);
return {
user: userData
};
}; 스타일링
SvelteKit은 다양한 스타일링 방식을 지원합니다.
컴포넌트 스코프 CSS
<script lang="ts">let count = 0;
</script>
<button on:click={() => count++}>
클릭 {count}번
</button>
<style>
button {
background: linear-gradient(to right, #667eea, #764ba2);
color: white;
padding: 1rem 2rem;
border: none;
border-radius: 0.5rem;
cursor: pointer;
font-size: 1rem;
transition: transform 0.2s;
}
button:hover {
transform: scale(1.05);
}
</style> Tailwind CSS 통합
이 블로그에서 사용하는 방식입니다:
# Tailwind CSS 4.0 설치
npm install -D tailwindcss@next @tailwindcss/vite@next
# PostCSS 및 Autoprefixer
npm install -D postcss autoprefixer vite.config.ts 설정:
import { sveltekit } from '@sveltejs/kit/vite';
import tailwindcss from '@tailwindcss/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
sveltekit(),
tailwindcss()
]
}); src/app.css:
@import "tailwindcss"; 사용 예:
<div class="max-w-4xl mx-auto px-4 py-12">
<h1 class="text-4xl font-bold text-gray-900 dark:text-white mb-6">
안녕하세요!
</h1>
<p class="text-lg text-gray-600 dark:text-gray-400">
Tailwind CSS를 사용한 스타일링
</p>
</div> API 라우트 만들기
SvelteKit에서는 API 엔드포인트도 쉽게 만들 수 있습니다:
// src/routes/api/posts/+server.ts
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
export const GET: RequestHandler = async () => {
const posts = await db.getPosts();
return json(posts);
};
export const POST: RequestHandler = async ({ request }) => {
const data = await request.json();
const newPost = await db.createPost(data);
return json(newPost, { status: 201 });
}; 배포하기
정적 사이트로 배포 (이 블로그 방식)
# adapter-static 설치
npm install -D @sveltejs/adapter-static
# svelte.config.js 설정
import adapter from '@sveltejs/adapter-static';
export default {
kit: {
adapter: adapter({
pages: 'build',
assets: 'build',
fallback: undefined,
precompress: false,
strict: true
})
}
};
# 빌드 및 프리뷰
npm run build
npm run preview 다양한 플랫폼에 배포
SvelteKit은 다양한 어댑터를 제공합니다:
- Vercel:
@sveltejs/adapter-vercel - Netlify:
@sveltejs/adapter-netlify - Cloudflare Pages:
@sveltejs/adapter-cloudflare - Node.js:
@sveltejs/adapter-node - 정적 사이트:
@sveltejs/adapter-static
실전 팁과 모범 사례
1. 레이아웃 활용하기
공통 UI 요소는 레이아웃으로 분리:
<!-- src/routes/+layout.svelte -->
<script lang="ts">import Header from "$lib/components/Header.svelte";
import Footer from "$lib/components/Footer.svelte";
</script>
<div class="app">
<Header />
<main>
<slot />
</main>
<Footer />
</div> 2. Load 함수 적극 활용
데이터는 항상 load 함수에서 가져오기:
// ✅ 좋은 예
export const load = async () => {
const data = await fetchData();
return { data };
};
// ❌ 나쁜 예 - 컴포넌트에서 직접 fetch
// onMount(async () => {
// data = await fetch(...);
// }); 3. 에러 처리
<!-- src/routes/+error.svelte -->
<script lang="ts">import { page } from "$app/stores";
</script>
<div class="error-page">
<h1>{$page.status}</h1>
<p>{$page.error?.message}</p>
<a href="/">홈으로 돌아가기</a>
</div> 4. TypeScript 활용
// src/lib/types.ts
export interface Post {
slug: string;
title: string;
date: string;
description: string;
content: string;
tags: string[];
}
// src/routes/blog/+page.server.ts
import type { PageServerLoad } from './$types';
import type { Post } from '$lib/types';
export const load: PageServerLoad = async () => {
const posts: Post[] = await getPosts();
return { posts };
}; 5. 이미지 최적화
<picture>
<source
srcset="/images/hero.webp"
type="image/webp"
>
<img
src="/images/hero.jpg"
alt="Hero image"
loading="lazy"
width="800"
height="600"
>
</picture> 성능 최적화
Prerendering
정적 페이지는 빌드 시 미리 렌더링:
// src/routes/about/+page.ts
export const prerender = true; Code Splitting
자동으로 코드가 분할되지만, 필요시 수동 제어:
// 동적 import로 필요할 때만 로드
const HeavyComponent = await import('$lib/components/HeavyComponent.svelte'); 디버깅 팁
개발 도구
<script lang="ts">import { dev } from "$app/environment";
$: if (dev) {
console.log("Current data:", data);
}
</script> 에러 추적
import { handleError } from '@sveltejs/kit';
export const handle = async ({ event, resolve }) => {
try {
return await resolve(event);
} catch (error) {
console.error('Error:', error);
throw error;
}
}; 마무리
SvelteKit은 현대적인 웹 애플리케이션을 만들기 위한 최고의 선택 중 하나입니다.
핵심 요점:
- 📁 직관적인 파일 기반 라우팅
- ⚡ 뛰어난 성능과 작은 번들 크기
- 🔧 유연한 배포 옵션
- 💎 훌륭한 개발 경험
- 🎨 다양한 스타일링 옵션
이 블로그도 SvelteKit으로 만들어졌습니다! 실제 프로덕션 환경에서 SvelteKit의 강력함을 직접 경험하고 있습니다.
더 알아보기
다음 포스트에서는 SvelteKit의 고급 패턴과 실전 기법을 다뤄보겠습니다. 기대해주세요!
Happy coding! 🚀
질문이나 피드백이 있으신가요?
이 튜토리얼에 대한 질문이나 제안사항이 있다면 언제든 연락주세요!
📧 이메일: [email protected]