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つのフェーズとレンダリングモード

  1. 開発: Svelteコンポーネントの作成とTypeScriptでの型定義
  2. ビルド: コンパイルと最適化、成果物の生成
  3. 実行:
    • 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
null
詳細を学ぶ

プロジェクト構造 ルーティング で詳しく解説しています。

レンダリングモード

ページごとに最適なレンダリング方式を選択できます。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
  };
};
typescript

+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' ? 'クライアント' : 'サーバー'
  };
};
typescript

+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>
svelte
詳細を学ぶ

Load関数とデータフェッチング でLoad関数の使い方と、内部動作を解説しています。

APIルート

同一プロジェクト内でRESTful APIを構築できます。フロントエンドとバックエンドが統合された開発体験を提供します。

ダイアグラムを読み込み中...

APIルートの特徴

  • 統一されたプロジェクト: フロントエンドとAPIが同じコードベース
  • 型安全: TypeScriptで型定義を共有
  • HTTPメソッド対応: GET、POST、PUT、DELETE、PATCHをサポート
  • 自動ルーティング: ファイル名(+server.ts)でエンドポイント作成

APIルートのデータフロー実装例

以下のシーケンス図は、クライアントと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()
  });
};
typescript

+page.svelte(フロントエンド)

+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>
svelte
詳細を学ぶ

APIルート設計 でRESTful APIの構築方法を詳しく解説しています。

プログレッシブエンハンスメント

JavaScriptが無効でも動作する堅牢なアプリケーションを構築できます。SvelteKitは「まずHTMLで動作し、JavaScriptで強化する」という設計思想を採用しています。これにより、ネットワーク環境が悪い場合やJavaScriptの読み込みに失敗した場合でも、基本機能は確実に動作します。

ダイアグラムを読み込み中...

実践的な例

1. 基本のHTML(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>
html
2. CSSで見た目と使い勝手を改善
/* 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;
}
css
3. JavaScriptで強化(use:enhance)
<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>
svelte

プログレッシブエンハンスメントの利点

  • アクセシビリティ向上: スクリーンリーダーや低速回線でも確実に動作
  • SEO最適化: 検索エンジンが内容を正しく理解
  • 信頼性: JavaScriptエラーが発生しても基本機能は維持
  • パフォーマンス: 初期表示が高速で、段階的に機能を追加
詳細を学ぶ

フォーム処理とActions で実装方法を詳しく解説しています。

型安全性

TypeScriptによる完全な型サポートで、開発時のエラーを防ぎます。SvelteKitは各ルートごとに型定義を自動生成し、load関数の引数と戻り値、Form Actionsの型などを完全に型付けします。

// ./$typesから自動生成される型
// PageLoadやPageDataなどの型は、実際のコードから自動的に推論・生成される
import type { PageLoad } from './$types';

export const load: PageLoad = async () => {
  // 型安全なデータ取得
};
typescript
詳細を学ぶ

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などの主要プラットフォームを自動認識
  }
};
javascript

同じコードベースから、設定を変えるだけで、

  • 静的サイト (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
bash

これだけで以下がすべて設定済み

  • 開発サーバー: HMR(ホットモジュールリプレースメント)対応
  • TypeScript: 型チェックとインテリセンス
  • ルーティング: ファイルベースの自動ルーティング
  • ビルドツール: Viteによる高速ビルド
  • CSS処理: PostCSS、Sass、Tailwind対応
  • テスト環境: Vitest、Playwright設定済み
  • Linter/Formatter: ESLint、Prettier設定済み

必要に応じて追加

ゼロコンフィグでも、必要な時に簡単に拡張可能

// vite.config.js - 必要な時だけカスタマイズ
export default defineConfig({
  // デフォルト設定を上書き
  // 例:プロキシ設定、エイリアス設定、プラグイン追加など
  // 基本的な開発では触る必要なし
});
javascript
開発効率

webpack.config.jsのような複雑な設定ファイルは不要。SvelteKitが最適な設定を提供し、必要な時だけオーバーライドできます。

パフォーマンスの優位性

SvelteKitはコンパイル時最適化により、他フレームワークより小さいバンドルサイズを実現します。

ダイアグラムを読み込み中...
詳細を学ぶ

パフォーマンス最適化の詳細は、最適化編で解説予定です。

なぜSvelteKitを選ぶのか

他フレームワークとの比較

項目SvelteKitNext.jsNuxtRemix
初期バンドル~40KB~70KB~65KB~60KB
Virtual DOM不要必要必要必要
学習曲線緩やか
SvelteKitの優位性
  • パフォーマンス: 最小のバンドルサイズと高速実行
  • シンプルさ: 少ない記述量で多くを実現
  • Web標準準拠: 標準に近いAPI設計

まとめ

SvelteKitは、Svelteの優れたパフォーマンスとシンプルさを活かしたフルスタックフレームワークです。ファイルベースルーティング、柔軟なレンダリングモード、プログレッシブエンハンスメントなど、モダンなWebアプリケーション開発に必要な機能をすべて備えています。

次のステップ

  1. プロジェクト構造 - ファイル構成と規約を理解する
  2. 特殊ファイルシステム - 各ファイルの役割と実行環境
  3. レンダリング戦略 - SSR・SSG・SPAの選択と実装
  4. ルーティング - URL設計とナビゲーション
  5. Load関数とデータフェッチング - データ取得戦略
Last update at: 2025/09/16 03:33:57