この記事の要点
• Svelteのリアクティビティとコンポーネント設計
• runesによる新しいリアクティブ宣言(Svelte 5)
• ストア・条件付きレンダリング・非同期データ取得
このチュートリアルで学ぶこと
- ✓ Svelteプロジェクトのセットアップ (Vite)
- ✓ コンポーネントとprops
- ✓ リアクティビティ (runes含む)
- ✓ イベント処理と双方向バインディング
- ✓ ストアによる状態管理
- ✓ 条件付き / ループレンダリング
前提条件
- HTML / CSS / JavaScript の基礎
- Node.js 20 以上
- npm または pnpm の使い方
- コンポーネント指向UIの概念を少しでも知っていると理解しやすい
プロジェクトのセットアップ
# Vite + Svelte テンプレート
npm create vite@latest my-svelte-app -- --template svelte-ts
cd my-svelte-app
npm install
npm run dev
ディレクトリ構造
my-svelte-app/
├── src/
│ ├── App.svelte
│ ├── main.ts
│ ├── lib/
│ │ └── Counter.svelte
│ └── app.css
├── index.html
├── svelte.config.js
├── vite.config.ts
└── tsconfig.json
ポイント: Svelteはコンパイル時に最適化されるため、仮想DOMを使わず直接DOMを操作します。バンドルサイズが小さく高速なのが最大の強みです。
基本概念
Svelteは「実行時フレームワーク」ではなく「コンパイラ」です。
.svelte ファイルはビルド時に最適化されたVanilla JSへ変換されるため、ランタイムが非常に小さく、
起動が速く、バンドルサイズも小さくなります。Svelte 5からは runes と呼ばれる新しいリアクティビティAPIが導入されました。
.svelte → コンパイラ → 最小限のJS + DOM操作
Step 1: 最初のコンポーネント
Svelteのコンポーネントは.svelteファイルにscript、markup、styleをまとめて記述します。
こんにちは、{name}!
bind:value により input と変数が双方向で同期します。
実践メモ: Svelte 5のrunes($state, $derived, $effect)を使うと、より明示的で予測可能なリアクティビティが実現できます。新規プロジェクトではrunesの利用を推奨します。
Step 2: runesを使ったリアクティビティ (Svelte 5)
2倍: {doubled}
$stateで宣言した値は変更を追跡される$derivedは依存値から算出される値$effectは副作用を実行 (マウント後に走る)
Step 3: propsとコンポーネント合成
{title}
{#if description}
{description}
{/if}
{@render children?.()}
{#snippet children()}
{/snippet}
Step 4: 条件とループ
ToDo リスト
{#if todos.length === 0}
タスクがありません
{:else}
{#each todos as todo (todo.id)}
-
toggle(todo.id)} />
{todo.text}
{/each}
{/if}
注意: writableストアはグローバルな状態管理に便利ですが、多用しすぎるとデータフローが追いにくくなります。コンポーネントpropsで済む場合はストアを使わないのが原則です。
Step 5: グローバルストア
// src/lib/stores/user.svelte.ts
type User = { name: string; loggedIn: boolean };
function createUserStore() {
let state = $state<User>({ name: "", loggedIn: false });
return {
get value() {
return state;
},
login(name: string) {
state = { name, loggedIn: true };
},
logout() {
state = { name: "", loggedIn: false };
},
};
}
export const userStore = createUserStore();
{#if userStore.value.loggedIn}
ようこそ {userStore.value.name} さん
{:else}
{/if}
Step 6: 非同期データ取得
{#await promise}
読み込み中...
{:then posts}
{#each posts as post}
- {post.title}
{/each}
{:catch error}
{error.message}
{/await}
完成コード: ミニメモアプリ
メモ
{#each sorted as memo (memo.id)}
-
{memo.title}
{memo.body}
{new Date(memo.updatedAt).toLocaleString()}
{/each}
よくあるエラーと対処
-
“Cannot assign to import” エラー
- ストアは関数でラップして getter/setter を提供する
-
$state の再代入がUIに反映されない
- 配列/オブジェクトは新しい参照を代入する (push だけでは検知できない場合あり)
-
runes の使用で TypeScript エラー
- svelte-check と @sveltejs/vite-plugin-svelte を最新に
-
{#each} で key を指定せず DOM が崩れる
- {#each items as item (item.id)} のように key を指定
-
onclick で () => func(arg) ではなく func(arg) と書いて即時実行される
- 必ず関数を渡す: onclick={() => func(arg)}
ベストプラクティス
- runes API ($state/$derived/$effect) を積極的に使う
- コンポーネントは小さく、責務を明確に
- グローバル状態はストアに集約
- $effect は本当に副作用が必要な場合のみ使用
- CSSはコンポーネントにスコープされる特性を活かす
- ブラウザAPIに依存するコードは onMount 相当の $effect 内で
次のステップ
- SvelteKit (公式フルスタックフレームワーク)
- Svelteのトランジション・アニメーション
- TypeScriptとの深い統合
- テスト (Vitest + @testing-library/svelte)
- デプロイ (Vercel / Netlify / Cloudflare Pages)
まとめ
Svelteはコンパイル時に最適化を行うため、ランタイムが小さく高速です。 runes APIの導入でより明示的で予測可能なリアクティビティを手に入れ、 学習コストも低いため小〜中規模アプリに特に向いています。
FAQ
Q. Svelte 4 と Svelte 5 の違いは?
A. Svelte 5 では runes ($state / $derived / $effect / $props) が導入され、
リアクティビティがより明示的になりました。既存のSvelte 4コードとも互換性がありますが、
新規開発はrunes前提で学ぶのがおすすめです。
Q. React との主な違いは?
A. ReactはVirtual DOMを使うランタイム中心、Svelteはコンパイル時に最適化するコンパイラ中心です。
Svelteは .svelte という単一ファイルにHTML/CSS/JSをまとめ、記述量が少なくなる傾向にあります。
Q. SvelteKit とは? A. Next.jsに相当する公式フルスタックフレームワークです。 ルーティング、サーバ機能、SSR/SSG/SPAの切替などが統合されています。
Q. 状態管理ライブラリは必要?
A. 小〜中規模ではストアパターンで十分です。大規模になる場合でも getContext / setContext や
runes を使った独自ストアで十分カバーできます。
チートシート
// Svelte 5 / Vite
// https://svelte.dev/docs
$state(value) // リアクティブな状態
$derived(expr) // 算出値
$effect(() => {...}) // 副作用
$props() // コンポーネントのprops
bind:value // 双方向バインディング
on* // onclick, oninput // イベントハンドラ (Svelte 5)
{#if} {:else} // 条件レンダリング
{#each items as item} // ループ
{#await promise} // 非同期レンダリング
{@render snippet()} // スニペット呼び出し
参考リソース
補足: スタイルとトランジション
Svelteはコンポーネントの <style> が自動的にスコープされるため、
クラス名の衝突を気にせずCSSを書けます。
{#if visible}
フライトイン / アウト
{/if}
{#if visible}
フェード
{/if}
transition: ディレクティブを使うことで、DOMが現れる / 消えるタイミングに
滑らかなアニメーションを追加できます。in: / out: を使って入退場を別々に指定することも可能です。