SvelteKit概要
SvelteKitは、Svelteを基盤としたフルスタックWebアプリケーションフレームワークです。このページでは、SvelteKitの全体像と基本的な概念を理解します。
SvelteKitとは何か
Svelteをベースにしたフルスタックフレームワークで、サーバーサイド機能とクライアントサイド機能を統合し、モダンなWebアプリケーションを効率的に構築できます。
フレームワークの位置づけ
Next.js(React)やNuxt(Vue)に相当する位置づけでありながら、より軽量で高速、そして開発者体験に優れた設計となっています。以下の図は、各フロントエンドフレームワークとそれに対応するフルスタックフレームワークの関係を示しています。
主要な特徴
SvelteKitは開発効率とパフォーマンスを両立させる多くの機能を標準で提供しています。これらの機能は追加設定なしで利用可能で、プロジェクトの立ち上げから本番デプロイまでをスムーズに行えます。
特徴 | 説明 |
---|---|
ファイルベースルーティング | ディレクトリ構造がそのままURLになる |
サーバーサイドレンダリング(SSR) | SEO最適化と初期表示の高速化 |
静的サイト生成(SSG) | ビルド時にHTMLを生成 |
APIルート | バックエンドAPIを同一プロジェクトで管理 |
プログレッシブエンハンスメント | JavaScriptなしでも動作する堅牢性 |
型安全性 | TypeScriptによる完全な型サポート |
ゼロコンフィグ | 設定なしですぐに開発開始可能 |
基本的な動作フロー
SvelteKitがどのように動作するか、開発からデプロイまでの流れを理解しましょう。SvelteKitは開発者が書いたコードを、選択したレンダリングモード(SSR/SSG/CSR)に応じて最適な形に変換し、ブラウザに配信します。
3つのフェーズとレンダリングモード
- 開発: Svelteコンポーネントの作成とTypeScriptでの型定義
- ビルド: コンパイルと最適化、成果物の生成
- 実行:
- SSR: サーバーでリクエスト時にHTML生成
- SSG: ビルド時に事前にHTML生成
- CSR/SPA: ブラウザでJavaScriptによりレンダリング
ファイルベースルーティング
SvelteKitでは、ディレクトリ構造がそのままURLになる直感的なルーティングシステムを採用しています。ファイルを作成するだけで自動的にルートが生成され、複雑なルーティング設定は不要です。
以下は、ディレクトリ構造とURLの対応関係を示しています。
src/routes/
├── +page.svelte → /
├── about/+page.svelte → /about
└── blog/
├── +page.svelte → /blog
└── [id]/+page.svelte → /blog/:id
レンダリングモード
ページごとに最適なレンダリング方式を選択できます。SvelteKitは3つの主要なレンダリングモードをサポートし、ページの特性に応じて最適な方式を選択することで、パフォーマンスとUXを最大化できます。
モード | 用途 | 特徴 |
---|---|---|
SSR | 動的コンテンツ | SEO対応、リアルタイムデータ |
SSG | 静的コンテンツ | 最高速、CDN配信可能 |
CSR | インタラクティブアプリ | SPA体験、クライアント処理 |
レンダリング戦略 及び、 レンダリング戦略とアーキテクチャパターン で各戦略を深く解説しています。
Load関数とデータフェッチング
Load関数は、ページのレンダリング前に必要なデータを取得し、コンポーネントに自動的に渡す仕組みを提供します。サーバーとクライアントの両方でデータを取得できる統一されたパターンです。
Load関数の主要な特徴
- Universal Load (
+page.ts
): サーバーとクライアント両方で実行可能、公開データの取得に最適 - Server Load (
+page.server.ts
): サーバーのみで実行、秘密情報やDB接続を安全に扱える - 自動的な型生成: TypeScriptの型が自動生成され、完全な型安全性を実現
データフローの実装例
+page.server.ts(サーバーのみで実行)
import type { PageServerLoad } from './$types';
export const load: PageServerLoad = async () => {
// 1. サーバー側でのみ実行(DBアクセスや秘密情報を扱える)
// このファイルはブラウザに送信されないため、環境変数やDBクレデンシャルを安全に使用可能
const secretData = await fetchFromDatabase();
console.log('1️⃣ +page.server.ts実行中(サーバー)');
return {
// このデータは+page.tsのload関数にdataプロパティとして渡される
serverMessage: 'サーバーからのデータ',
timestamp: new Date().toISOString(),
secretData
};
};
+page.ts(サーバー→クライアント両方で実行)
import type { PageLoad } from './$types';
export const load: PageLoad = async ({ data, fetch }) => {
// 2. サーバー側(SSR時)で実行
// 3. その後、クライアント側(ハイドレーション時)でも実行
// fetchはSvelteKitが提供する拡張版で、SSR時にはサーバー内部で、クライアントではブラウザのfetchを使用
console.log('2️⃣ +page.ts実行中');
console.log('サーバーから受け取ったデータ:', data);
// 追加のデータ取得(公開API等)
const publicData = await fetch('/api/public').then(r => r.json());
return {
// +page.server.tsからのデータを含める
...data,
// 追加のデータ
publicData,
isClient: typeof window !== 'undefined' ? 'クライアント' : 'サーバー'
};
};
+page.svelte(コンポーネント)
<script lang="ts">
import type { PageData } from './$types';
// 4. 最終的にコンポーネントがデータを受け取る
// PageDataは自動生成される型で、load関数の戻り値と完全に一致
let { data }: { data: PageData } = $props();
</script>
<div>
<h2>データフローの確認</h2>
<p>サーバーメッセージ: {data.serverMessage}</p>
<p>タイムスタンプ: {data.timestamp}</p>
<p>実行環境: {data.isClient}</p>
<p>公開データ: {JSON.stringify(data.publicData)}</p>
</div>
Load関数とデータフェッチング でLoad関数の使い方と、内部動作を解説しています。
APIルート
同一プロジェクト内でRESTful APIを構築できます。フロントエンドとバックエンドが統合された開発体験を提供します。
APIルートの特徴
- 統一されたプロジェクト: フロントエンドとAPIが同じコードベース
- 型安全: TypeScriptで型定義を共有
- HTTPメソッド対応: GET、POST、PUT、DELETE、PATCHをサポート
- 自動ルーティング: ファイル名(
+server.ts
)でエンドポイント作成
APIルートのデータフロー実装例
以下のシーケンス図は、クライアントとAPIルート間のデータの流れを示しています。
/api/posts/+server.ts(APIエンドポイント)
import { json } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
// 1️⃣ GET: 投稿一覧を取得
// HTTPのGETメソッドに対応する関数をexportすることで、自動的にエンドポイントが作成される
export const GET: RequestHandler = async ({ url }) => {
console.log('🔵 GET /api/posts - サーバー側で実行');
// クエリパラメータを取得
const limit = Number(url.searchParams.get('limit')) || 10;
// データベースから投稿を取得(例)
const posts = await fetchPostsFromDB(limit);
return json({
posts,
timestamp: new Date().toISOString(),
method: 'GET'
});
};
// 2️⃣ POST: 新しい投稿を作成
// POSTメソッドでデータを受け取り、バリデーション後にDBへ保存
export const POST: RequestHandler = async ({ request }) => {
console.log('🟢 POST /api/posts - サーバー側で実行');
// リクエストボディを取得
const body = await request.json();
// バリデーション
if (!body.title || !body.content) {
return json(
{ error: 'タイトルと内容は必須です' },
{ status: 400 }
);
}
// データベースに保存(例)
const newPost = await savePostToDB({
title: body.title,
content: body.content,
createdAt: new Date()
});
return json({
post: newPost,
message: '投稿が作成されました'
}, { status: 201 });
};
// 3️⃣ DELETE: 投稿を削除
// DELETEメソッドでリソースの削除を処理。RESTfulな設計に準拠
export const DELETE: RequestHandler = async ({ url }) => {
console.log('🔴 DELETE /api/posts - サーバー側で実行');
const id = url.searchParams.get('id');
if (!id) {
return json(
{ error: 'IDが必要です' },
{ status: 400 }
);
}
await deletePostFromDB(id);
return json({
message: `投稿 ${id} が削除されました`,
deletedAt: new Date().toISOString()
});
};
+page.svelte(フロントエンド)
<script lang="ts">
import { onMount } from 'svelte';
type Post = {
id: string;
title: string;
content: string;
createdAt: string;
};
let posts: Post[] = [];
let newPost = { title: '', content: '' };
let loading = false;
// 4️⃣ ページ読み込み時に投稿を取得
// onMountはクライアントサイドでのみ実行される。SSR時には実行されない
onMount(async () => {
console.log('📱 クライアント: 投稿一覧を取得');
const response = await fetch('/api/posts?limit=5');
const data = await response.json();
posts = data.posts;
console.log(`📱 ${posts.length}件の投稿を受信`);
});
// 5️⃣ 新しい投稿を作成
// フォーム送信をJavaScriptで処理。プログレッシブエンハンスメントにより、JSなしでも動作可能
async function createPost() {
loading = true;
console.log('📱 クライアント: 新規投稿を送信');
const response = await fetch('/api/posts', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(newPost)
});
if (response.ok) {
const data = await response.json();
posts = [...posts, data.post];
newPost = { title: '', content: '' };
console.log('📱 投稿作成成功:', data.message);
}
loading = false;
}
// 6️⃣ 投稿を削除
// DELETE メソッドを使用してRESTfulに削除処理。楽観的UIアップデートも実装可能
async function deletePost(id: string) {
console.log('📱 クライアント: 投稿削除リクエスト');
const response = await fetch(`/api/posts?id=${id}`, {
method: 'DELETE'
});
if (response.ok) {
const data = await response.json();
posts = posts.filter(p => p.id !== id);
console.log('📱 削除成功:', data.message);
}
}
</script>
<div>
<h2>APIルートのデモ</h2>
<!-- 投稿作成フォーム -->
<form on:submit|preventDefault={createPost}>
<input
bind:value={newPost.title}
placeholder="タイトル"
required
/>
<textarea
bind:value={newPost.content}
placeholder="内容"
required
/>
<button type="submit" disabled={loading}>
{loading ? '送信中...' : '投稿する'}
</button>
</form>
<!-- 投稿一覧 -->
<div class="posts">
{#each posts as post}
<article>
<h3>{post.title}</h3>
<p>{post.content}</p>
<button on:click={() => deletePost(post.id)}>
削除
</button>
</article>
{/each}
</div>
</div>
APIルート設計 でRESTful APIの構築方法を詳しく解説しています。
プログレッシブエンハンスメント
JavaScriptが無効でも動作する堅牢なアプリケーションを構築できます。SvelteKitは「まずHTMLで動作し、JavaScriptで強化する」という設計思想を採用しています。これにより、ネットワーク環境が悪い場合やJavaScriptの読み込みに失敗した場合でも、基本機能は確実に動作します。
実践的な例
<!-- JavaScriptなしでも動作する基本的なHTMLフォーム -->
<!-- action="?/login"はSvelteKitのForm Actions機能を使用 -->
<form method="POST" action="?/login">
<input name="email" type="email" required>
<input name="password" type="password" required>
<button type="submit">ログイン</button>
</form>
/* HTML5のバリデーション状態に応じたスタイリング */
/* CSSだけで入力状態を視覚的にフィードバック。JavaScriptは不要 */
input:required {
border-left: 3px solid #ff6b6b;
}
input:valid {
border-left: 3px solid #51cf66;
}
input:invalid:not(:placeholder-shown) {
background-color: #ffe3e3;
}
input:focus:invalid {
outline-color: #ff6b6b;
}
/* 無効な入力時のヒント表示 */
input:invalid:not(:placeholder-shown) + .hint {
display: block;
color: #ff6b6b;
}
<script>
import { enhance } from '$app/forms';
let loading = false;
// use:enhanceディレクティブでフォームを強化し、ページリロードなしで送信
</script>
<form method="POST" action="?/login" use:enhance={() => {
loading = true;
return async ({ update }) => {
await update();
loading = false;
};
}}>
<input name="email" type="email" required>
<input name="password" type="password" required>
<button type="submit" disabled={loading}>
{loading ? 'ログイン中...' : 'ログイン'}
</button>
</form>
プログレッシブエンハンスメントの利点
- アクセシビリティ向上: スクリーンリーダーや低速回線でも確実に動作
- SEO最適化: 検索エンジンが内容を正しく理解
- 信頼性: JavaScriptエラーが発生しても基本機能は維持
- パフォーマンス: 初期表示が高速で、段階的に機能を追加
フォーム処理とActions で実装方法を詳しく解説しています。
型安全性
TypeScriptによる完全な型サポートで、開発時のエラーを防ぎます。SvelteKitは各ルートごとに型定義を自動生成し、load関数の引数と戻り値、Form Actionsの型などを完全に型付けします。
// ./$typesから自動生成される型
// PageLoadやPageDataなどの型は、実際のコードから自動的に推論・生成される
import type { PageLoad } from './$types';
export const load: PageLoad = async () => {
// 型安全なデータ取得
};
SvelteKitが自動生成する型 で型システムの詳細を解説しています。
デプロイメント - アダプターシステム
SvelteKitのアダプターシステムにより、一つのコードベースから様々なプラットフォームへ最適化されたビルドを生成できます。
アダプターとは
アダプターは、SvelteKitアプリケーションを特定のホスティング環境向けに変換するプラグインです。
主要なアダプターの例
adapter-static
: GitHub Pages、S3などの静的ホスティング向けadapter-node
: Node.jsサーバー、Docker、VPS向けadapter-vercel
: Vercel のEdge/Serverless Functions向けadapter-cloudflare
: Cloudflare Workers/Pages向けadapter-auto
: プラットフォームを自動検出(推奨)
基本的な使い方
// svelte.config.js
import adapter from '@sveltejs/adapter-auto';
export default {
kit: {
adapter: adapter() // 自動でプラットフォームを検出
// adapter-autoは、Vercel、Netlify、Cloudflareなどの主要プラットフォームを自動認識
}
};
同じコードベースから、設定を変えるだけで、
- 静的サイト (HTML/CSS/JS)
- Node.jsアプリ (Express互換)
- エッジ関数 (Cloudflare Workers)
- サーバーレス関数 (Vercel、Netlify)
などに変換できます。
プラットフォーム別デプロイ で各アダプターの詳細設定とベストプラクティスを解説しています。
ゼロコンフィグ - すぐに始められる開発体験
SvelteKitは設定なしですぐに開発を始められるように設計されています。
デフォルトで含まれる機能
# 1. プロジェクト作成(対話形式でTypeScript、ESLint、Prettierなどを選択可能)
npm create svelte@latest my-app
# 2. プロジェクトディレクトリに移動
cd my-app
# 3. 依存関係をインストール
npm install
# 4. 開発サーバー起動(http://localhost:5173でアクセス可能)
npm run dev
これだけで以下がすべて設定済み
- ✅ 開発サーバー: HMR(ホットモジュールリプレースメント)対応
- ✅ TypeScript: 型チェックとインテリセンス
- ✅ ルーティング: ファイルベースの自動ルーティング
- ✅ ビルドツール: Viteによる高速ビルド
- ✅ CSS処理: PostCSS、Sass、Tailwind対応
- ✅ テスト環境: Vitest、Playwright設定済み
- ✅ Linter/Formatter: ESLint、Prettier設定済み
必要に応じて追加
ゼロコンフィグでも、必要な時に簡単に拡張可能
// vite.config.js - 必要な時だけカスタマイズ
export default defineConfig({
// デフォルト設定を上書き
// 例:プロキシ設定、エイリアス設定、プラグイン追加など
// 基本的な開発では触る必要なし
});
webpack.config.jsのような複雑な設定ファイルは不要。SvelteKitが最適な設定を提供し、必要な時だけオーバーライドできます。
パフォーマンスの優位性
SvelteKitはコンパイル時最適化により、他フレームワークより小さいバンドルサイズを実現します。
パフォーマンス最適化の詳細は、最適化編で解説予定です。
なぜSvelteKitを選ぶのか
他フレームワークとの比較
項目 | SvelteKit | Next.js | Nuxt | Remix |
---|---|---|---|---|
初期バンドル | ~40KB | ~70KB | ~65KB | ~60KB |
Virtual DOM | 不要 | 必要 | 必要 | 必要 |
学習曲線 | 緩やか | 急 | 中 | 中 |
- パフォーマンス: 最小のバンドルサイズと高速実行
- シンプルさ: 少ない記述量で多くを実現
- Web標準準拠: 標準に近いAPI設計
まとめ
SvelteKitは、Svelteの優れたパフォーマンスとシンプルさを活かしたフルスタックフレームワークです。ファイルベースルーティング、柔軟なレンダリングモード、プログレッシブエンハンスメントなど、モダンなWebアプリケーション開発に必要な機能をすべて備えています。
次のステップ
- プロジェクト構造 - ファイル構成と規約を理解する
- 特殊ファイルシステム - 各ファイルの役割と実行環境
- レンダリング戦略 - SSR・SSG・SPAの選択と実装
- ルーティング - URL設計とナビゲーション
- Load関数とデータフェッチング - データ取得戦略