Svelte 완벽 가이드 | 컴파일러 기반 프레임워크·Reactivity·SvelteKit·실전 활용

Svelte 완벽 가이드 | 컴파일러 기반 프레임워크·Reactivity·SvelteKit·실전 활용

이 글의 핵심

Svelte로 고성능 웹 앱을 개발하는 완벽 가이드입니다. Reactivity, Components, Stores, SvelteKit, TypeScript까지 실전 예제로 정리했습니다.

실무 경험 공유: React에서 Svelte로 전환하면서, 번들 크기가 70% 감소하고 성능이 크게 향상된 경험을 공유합니다.

들어가며: “Virtual DOM이 느려요”

실무 문제 시나리오

시나리오 1: 번들 크기가 커요
React는 런타임이 필요합니다. Svelte는 컴파일러라 작습니다.

시나리오 2: 보일러플레이트가 많아요
useState, useEffect가 번거롭습니다. Svelte는 간단합니다.

시나리오 3: 성능이 중요해요
Virtual DOM 오버헤드가 있습니다. Svelte는 컴파일 타임에 최적화합니다.


1. Svelte란?

핵심 특징

Svelte는 컴파일러 기반 프론트엔드 프레임워크입니다.

주요 장점:

  • 컴파일러: 런타임 없음
  • 작은 번들: 3KB
  • 빠른 성능: Virtual DOM 없음
  • 간단한 문법: 보일러플레이트 최소
  • Reactivity: 자동 반응형

2. 설치 및 프로젝트 생성

SvelteKit

npm create svelte@latest my-app
cd my-app
npm install
npm run dev

Vite + Svelte

npm create vite@latest my-app -- --template svelte-ts

3. 기본 컴포넌트

<script lang="ts">
  let count = 0;

  function increment() {
    count += 1;
  }
</script>

<div>
  <h1>Count: {count}</h1>
  <button on:click={increment}>Increment</button>
</div>

<style>
  div {
    padding: 2rem;
    text-align: center;
  }

  h1 {
    font-size: 2rem;
    color: #333;
  }

  button {
    padding: 0.5rem 1rem;
    background: #3498db;
    color: white;
    border: none;
    border-radius: 4px;
    cursor: pointer;
  }

  button:hover {
    opacity: 0.8;
  }
</style>

4. Reactivity

기본 Reactivity

<script lang="ts">
  let count = 0;
  $: doubled = count * 2;
  $: console.log(`Count is ${count}`);
</script>

<p>Count: {count}</p>
<p>Doubled: {doubled}</p>
<button on:click={() => count++}>Increment</button>

배열/객체 Reactivity

<script lang="ts">
  let items = [1, 2, 3];

  function addItem() {
    items = [...items, items.length + 1];
  }
</script>

<ul>
  {#each items as item}
    <li>{item}</li>
  {/each}
</ul>
<button on:click={addItem}>Add Item</button>

5. Props

<!-- Button.svelte -->
<script lang="ts">
  export let label: string;
  export let variant: 'primary' | 'secondary' = 'primary';
</script>

<button class={variant}>
  {label}
</button>

<style>
  .primary {
    background: #3498db;
    color: white;
  }

  .secondary {
    background: #2ecc71;
    color: white;
  }
</style>

<!-- App.svelte -->
<script lang="ts">
  import Button from './Button.svelte';
</script>

<Button label="Primary" variant="primary" />
<Button label="Secondary" variant="secondary" />

6. Stores

// stores.ts
import { writable, derived } from 'svelte/store';

export const count = writable(0);
export const doubled = derived(count, ($count) => $count * 2);

// Component.svelte
<script lang="ts">
  import { count, doubled } from './stores';
</script>

<p>Count: {$count}</p>
<p>Doubled: {$doubled}</p>
<button on:click={() => $count++}>Increment</button>

7. SvelteKit

파일 기반 라우팅

src/routes/
├── +page.svelte          # /
├── about/
│   └── +page.svelte      # /about
└── users/
    └── [id]/
        └── +page.svelte  # /users/:id

+page.svelte

<script lang="ts">
  export let data;
</script>

<h1>User: {data.user.name}</h1>

+page.ts (Loader)

import type { PageLoad } from './$types';

export const load: PageLoad = async ({ params, fetch }) => {
  const response = await fetch(`/api/users/${params.id}`);
  const user = await response.json();

  return { user };
};

8. Form Actions

<!-- +page.svelte -->
<script lang="ts">
  import { enhance } from '$app/forms';
</script>

<form method="POST" use:enhance>
  <input name="email" type="email" required />
  <input name="password" type="password" required />
  <button type="submit">Login</button>
</form>
// +page.server.ts
import type { Actions } from './$types';

export const actions: Actions = {
  default: async ({ request }) => {
    const data = await request.formData();
    const email = data.get('email');
    const password = data.get('password');

    // 로그인 로직
    return { success: true };
  },
};

9. 실전 예제: Todo 앱

<script lang="ts">
  interface Todo {
    id: number;
    text: string;
    done: boolean;
  }

  let todos: Todo[] = [
    { id: 1, text: 'Learn Svelte', done: false },
    { id: 2, text: 'Build an app', done: false },
  ];

  let newTodo = '';

  function addTodo() {
    if (!newTodo.trim()) return;

    todos = [...todos, { id: Date.now(), text: newTodo, done: false }];
    newTodo = '';
  }

  function toggleTodo(id: number) {
    todos = todos.map((todo) =>
      todo.id === id ? { ...todo, done: !todo.done } : todo
    );
  }

  function deleteTodo(id: number) {
    todos = todos.filter((todo) => todo.id !== id);
  }

  $: remaining = todos.filter((t) => !t.done).length;
</script>

<div class="container">
  <h1>Todo App</h1>

  <div class="input-group">
    <input
      bind:value={newTodo}
      on:keydown={(e) => e.key === 'Enter' && addTodo()}
      placeholder="Add todo"
    />
    <button on:click={addTodo}>Add</button>
  </div>

  <p>{remaining} remaining</p>

  <ul>
    {#each todos as todo (todo.id)}
      <li class:done={todo.done}>
        <input type="checkbox" checked={todo.done} on:change={() => toggleTodo(todo.id)} />
        <span>{todo.text}</span>
        <button on:click={() => deleteTodo(todo.id)}>Delete</button>
      </li>
    {/each}
  </ul>
</div>

<style>
  .container {
    max-width: 600px;
    margin: 0 auto;
    padding: 2rem;
  }

  .input-group {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1rem;
  }

  input[type='text'] {
    flex: 1;
    padding: 0.5rem;
    border: 1px solid #ddd;
    border-radius: 4px;
  }

  ul {
    list-style: none;
    padding: 0;
  }

  li {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem;
    border-bottom: 1px solid #eee;
  }

  li.done span {
    text-decoration: line-through;
    opacity: 0.5;
  }
</style>

정리 및 체크리스트

핵심 요약

  • Svelte: 컴파일러 기반 프레임워크
  • 작은 번들: 3KB
  • 빠른 성능: Virtual DOM 없음
  • 간단한 문법: 보일러플레이트 최소
  • Reactivity: 자동 반응형
  • SvelteKit: 풀스택 프레임워크

구현 체크리스트

  • Svelte 설치
  • 기본 컴포넌트 작성
  • Reactivity 활용
  • Props 전달
  • Stores 사용
  • SvelteKit 구현
  • Form Actions
  • 배포

같이 보면 좋은 글

  • React 완벽 가이드
  • Vue 3 Composition API 가이드
  • SvelteKit 완벽 가이드

이 글에서 다루는 키워드

Svelte, SvelteKit, Compiler, Reactivity, Frontend, TypeScript, Performance

자주 묻는 질문 (FAQ)

Q. React와 비교하면 어떤가요?

A. Svelte가 더 간단하고 빠릅니다. React는 생태계가 더 큽니다.

Q. 학습 곡선은 어떤가요?

A. React보다 낮습니다. 문법이 간단합니다.

Q. 프로덕션에서 사용해도 되나요?

A. 네, 많은 기업에서 안정적으로 사용하고 있습니다.

Q. TypeScript를 지원하나요?

A. 네, 완벽하게 지원합니다.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3