Load関数の基礎

このページでは、SvelteKitの中核機能であるLoad関数の基本的な使い方を学びます。

Load関数とは何か?

Load関数は、SvelteKitにおけるデータフェッチングの中心的な仕組みです。ページやレイアウトがレンダリングされる前に必要なデータを取得し、コンポーネントに渡す役割を担います。

主な特徴

  1. 自動実行: SvelteKitがページ遷移時に自動的にload関数を呼び出し、結果をコンポーネントに渡す(開発者が手動で呼び出す必要がない)
  2. 非同期処理: async/awaitを使った非同期データ取得が可能
  3. 型安全: TypeScriptとの完全な統合により型安全性を保証
  4. 最適化: SvelteKitが自動的にキャッシュやプリフェッチを最適化
「自動実行」の意味

自動実行とは「開発者が明示的に呼び出さなくても良い」という意味です。

React等では、

// React - useEffectで手動実行
useEffect(() => {
  fetchData(); // 開発者が明示的に呼び出す
}, []);
javascript

SvelteKitでは、

// +page.ts に定義するだけ
export const load: PageLoad = async ({ params, fetch }) => {
  // paramsやfetchの型が自動推論される
  return {
    post: await fetch(`/api/posts/${params.id}`).then(r => r.json())
  };
};
// コンポーネント側でload()を呼ぶ必要はない!
typescript

なぜLoad関数が必要か?

従来のSPAでは、コンポーネントのマウント後にデータを取得することが一般的でした。しかし、これには以下の問題があります。

  • SEOの問題: 初期HTMLにデータが含まれない
  • パフォーマンス: 画面表示後にローディングが発生
  • ウォーターフォール: 親子コンポーネントで順次データ取得

Load関数はこれらの問題を解決します。

データ取得パターンの比較

従来のSPAパターン(避けるべき)

データがコンポーネントマウント後にデータ取得される。

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

コード例

<script lang="ts">
  import { onMount } from 'svelte';
  let data = null;
  
  onMount(async () => {
    // コンポーネントマウント後にデータ取得
    const response = await fetch('/api/data');
    data = await response.json();
  });
</script>
svelte

SvelteKitのLoad関数パターン(推奨)

データは自動的に実行されるload関数を呼び出し時にfetchにて取得され、その結果をコンポーネントに渡され、データが反映された状態で表示される。

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

コード例

// +page.ts
export const load = async ({ fetch }) => {
  // ページ表示前にデータ取得
  const response = await fetch('/api/data');
  const data = await response.json();
  
  return { data };
};
svelte

Load関数の実行タイミング

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

2種類のLoad関数

SvelteKitには2種類のLoad関数があります。それぞれ異なる実行環境と用途があり、適切に使い分けることでセキュリティとパフォーマンスを両立できます。

Universal Load (+page.ts / +layout.ts)

サーバーとクライアントの両方で実行される関数です。初回アクセス時はSSRのためサーバーで実行され、クライアントサイドナビゲーション時はブラウザで実行されます。これにより、SEOとユーザー体験の両方を最適化できます。

ダイアグラムを読み込み中...
⚡ 特徴
  • SSR時はサーバーで実行
  • クライアントサイドナビゲーション時はブラウザで実行
  • 公開APIの呼び出しに適している
  • fetchは自動的に最適化される
🎯 適している用途
  • 公開APIの呼び出し
  • URLパラメータの処理
  • クライアント側でも必要なデータ
  • CDNでキャッシュ可能なデータ

基本的な使用例

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

export const load: PageLoad = async ({ params, url, fetch }) => {
  // fetch関数はSvelteKitによって拡張され、
  // サーバー/クライアント両方で動作する
  const response = await fetch('/api/data');
  const data = await response.json();
  
  return {
    data  // このデータはコンポーネントの`data`プロップに渡される
  };
};
typescript

実践的な使用例

// +page.ts
export const load: PageLoad = async ({ fetch, url }) => {
  // ✅ 公開APIの呼び出し
  const posts = await fetch('/api/posts').then(r => r.json());
  
  // ✅ URLパラメータの処理
  const page = url.searchParams.get('page') || '1';
  
  // ✅ クライアントでも必要な計算
  const currentPage = parseInt(page);
  
  return {
    posts,
    currentPage
  };
};
typescript

Server Load (+page.server.ts / +layout.server.ts)

サーバーサイドでのみ実行される関数です。データベースへの直接アクセスや秘密情報の取り扱いが可能で、セキュリティを保ちながらバックエンド処理を実装できます。

ダイアグラムを読み込み中...
🔒 特徴
  • 常にサーバーサイドで実行
  • 秘密情報(APIキー、DB認証情報)を安全に扱える
  • データベースに直接アクセス可能
  • Node.js専用のライブラリを使用可能
🎯 適している用途
  • データベースアクセス
  • 認証・認可処理
  • 秘密情報の使用
  • ファイルシステムアクセス
  • サーバーサイド専用ライブラリ

基本的な使用例

// +page.server.ts
import type { PageServerLoad } from './$types';
import { db } from '$lib/server/database';

export const load: PageServerLoad = async ({ params, locals }) => {
  // データベースに直接アクセス可能
  // このコードはブラウザに送られないため安全
  const user = await db.user.findUnique({
    where: { id: params.id }
  });
  
  return {
    user  // シリアライズ可能なデータのみ返す
  };
};
typescript

実践的な使用例

// +page.server.ts
import { redirect } from '@sveltejs/kit';
import { PRIVATE_API_KEY } from '$env/static/private';
import fs from 'fs/promises';

export const load: PageServerLoad = async ({ cookies, locals, platform }) => {
  // ✅ 認証チェック
  const sessionId = cookies.get('session');
  if (!sessionId) throw redirect(303, '/login');
  
  // ✅ データベースアクセス
  const user = await db.user.findUnique({
    where: { sessionId }
  });
  
  // ✅ 秘密情報の使用
  const apiData = await fetch('https://api.example.com', {
    headers: {
      'Authorization': `Bearer ${PRIVATE_API_KEY}`
    }
  });
  
  // ✅ ファイルシステムアクセス
  const config = await fs.readFile('./config.json', 'utf-8');
  
  return {
    user,
    apiData: await apiData.json(),
    config: JSON.parse(config)
  };
};
typescript

比較表

項目Universal LoadServer Load
ファイル名+page.ts
+layout.ts
+page.server.ts
+layout.server.ts
型定義PageLoad
LayoutLoad
PageServerLoad
LayoutServerLoad
実行環境サーバー&クライアント両方サーバーのみ
SSR時サーバーで実行サーバーで実行
CSR時クライアントで実行サーバーで実行(API経由)
データベース❌ 直接アクセス不可✅ 直接アクセス可能
秘密情報❌ 扱えない(クライアントに露出)✅ 安全に扱える
Node.js API⚠️ SSR時のみ✅ 常に利用可能
ファイルシステム⚠️ SSR時のみ✅ 常に利用可能
実行タイミングナビゲーション前ナビゲーション前
キャッシュクライアント側でキャッシュ可能サーバー側で制御
バンドルサイズクライアントバンドルに含まれる含まれない

Load関数のパラメータ

共通パラメータ

両方のLoad関数で使用できるパラメータ

パラメータ説明
urlURLリクエストのURL(searchParamsを含む)
paramsRecord<string, string>動的ルートパラメータ([slug]など)
route{ id: string }現在のルートID
fetchFetchSvelteKit拡張版のfetch関数
setHeaders(headers: Record<string, string>) => voidレスポンスヘッダーを設定
depends(...deps: string[]) => void依存関係を宣言(invalidate用)
parent() => Promise<ParentData>親レイアウトのデータを取得

Universal Load専用パラメータ

パラメータ説明
dataPageDataServer Loadからのデータ(ある場合)

Server Load専用パラメータ

パラメータ説明
requestRequest元のHTTPリクエストオブジェクト
cookiesCookiesCookieの読み書きAPI
localsApp.LocalsHooksで設定したローカルデータ
platformApp.Platformプラットフォーム固有のデータ
isDataRequestbooleanデータリクエストかどうか
isSubRequestbooleanサブリクエストかどうか

Load関数の選び方

データ取得の要件に応じて、適切なLoad関数を選択します。

Server Loadを使用すべき場合

  1. 秘密情報の取り扱い

    • APIキーやデータベースクレデンシャル
    • サードパーティサービスのシークレット
    • 環境変数に保存された機密情報
  2. データベース直接アクセス

    • Prisma、Drizzle ORMなどのORM使用
    • SQLクエリの直接実行
    • RedisやMongoDBへの接続
  3. サーバーサイド専用ライブラリ

    • Node.js専用モジュールの使用
    • ファイルシステムへのアクセス
    • システムコマンドの実行
// 例:Server Loadが適切なケース
export const load: PageServerLoad = async ({ locals }) => {
  // データベースに直接アクセス
  const posts = await db.post.findMany({
    where: { userId: locals.session.userId }
  });

  // 秘密のAPIキーを使用
  const analytics = await fetchWithSecret(process.env.ANALYTICS_KEY);

  return { posts, analytics };
};
typescript

Universal Loadを使用すべき場合

  1. 公開APIの呼び出し

    • REST APIエンドポイント
    • GraphQLクエリ
    • パブリックAPIのデータ
  2. SEOが重要な場合

    • サーバーサイドレンダリングが必要
    • メタデータの動的生成
    • Open Graphタグの設定
  3. クライアントサイド再実行

    • ナビゲーション時のデータ更新
    • リアルタイム更新が必要
    • クライアントサイドキャッシュの活用
// 例:Universal Loadが適切なケース
export const load: PageLoad = async ({ fetch, params }) => {
  // 公開APIからデータ取得
  const response = await fetch(`/api/posts/${params.id}`);
  const post = await response.json();

  // クライアントサイドでも再実行可能
  return { post };
};
typescript

選択フローチャート

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

async/awaitの実行タイミングと並列処理

Load関数内でのasync/awaitの実行タイミングと並列処理による最適化の詳細については、 データフローの詳細 ページで解説しています。

TypeScript型の自動生成システム

SvelteKitの型安全なデータ取得と./$typesの自動生成システムの詳細は、 TypeScript型の自動生成システム の専用ページで解説しています。

レイアウトとページ間のデータ共有

レイアウトとページ間でデータを共有する方法です。SvelteKitはレイアウトのLoad関数を先に実行し、そのデータをページのLoad関数で利用できるようにします。これにより、共通データの重複取得を避け、効率的なデータフローを実現します。

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

レイアウトのLoad関数でのデータ取得

レイアウトのLoad関数で取得したデータは、そのレイアウトに属するすべてのページで共有されます。一般的にユーザー情報や設定など、アプリケーション全体で必要なデータをここで取得します。

// +layout.server.ts
import type { LayoutServerLoad } from './$types';

export const load: LayoutServerLoad = async ({ locals }) => {
  // セッションからユーザー情報を取得
  // このデータはすべての子ページで利用可能
  const user = await getUserFromSession(locals.session);
  
  return {
    user  // このユーザー情報はこのレイアウトに属するすべてのページで利用可能
  };
};
typescript

ページのLoad関数でのデータ取得

ページのLoad関数でparent()関数を使って、上位レイアウトのデータにアクセスします。これにより、レイアウトで取得したデータを基に、追加のデータを取得できます。

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

export const load: PageLoad = async ({ parent }) => {
  // 上位レイアウトのデータを取得
  // parent()は上位のLoad関数の完了を待つ
  const { user } = await parent();
  
  // ユーザー固有のデータを取得
  // 親のデータを活用して追加情報を取得
  const posts = await fetch(`/api/users/${user.id}/posts`)
    .then(r => r.json());
  
  return {
    posts
    // userは自動的に継承される
    // 明示的に返さなくてもコンポーネントで利用可能
  };
};
typescript

実践的な例:ECサイトの商品詳細ページ

実際のECサイトを想定した、Load関数の実践的な使用例です。レイアウトでユーザー情報を取得し、ページで商品データを取得する典型的なパターンを示します。

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

この例では、以下の処理が行われています。

  1. レイアウトLoad(+layout.server.ts)

    • Redisからセッション情報を取得
    • ユーザー情報とカート情報を管理
  2. ページLoad(+page.server.ts)

    • parent()で親のユーザー情報を活用
    • PostgreSQLから商品情報を取得
    • AWS S3から署名付きURLを生成
    • レコメンド商品を取得
  3. Form Action

    • カート追加処理
    • 在庫確認とデータベース更新
    • セッション更新

エラーハンドリング

Load関数でのエラー処理方法です。適切なエラーハンドリングにより、ユーザーにわかりやすいエラーメッセージを表示し、アプリケーションの信頼性を向上させます。

基本的なエラー処理

SvelteKitのerror関数を使って、HTTPステータスコードとメッセージを持つエラーを投げます。これにより、適切なエラーページが表示されます。

import { error } from '@sveltejs/kit';
import type { PageLoad } from './$types';

export const load: PageLoad = async ({ params }) => {
  const response = await fetch(`/api/posts/${params.id}`);
  
  if (!response.ok) {
    // HTTPエラーを投げる
    // error関数はステータスコードとオプションデータを受け取る
    throw error(response.status, {
      message: 'Post not found'  // エラーページで表示されるメッセージ
    });
  }
  
  const post = await response.json();
  return { post };
};
typescript

カスタムエラーページ

+error.svelteファイルを作成して、エラーの表示をカスタマイズします。このファイルはLoad関数でエラーが発生したときに自動的に表示されます。

<!-- +error.svelte -->
<script lang="ts">
  import { page } from '$app/stores';
  // $pageストアからエラー情報にアクセス
</script>

<!-- HTTPステータスコードを表示 -->
<h1>{$page.status}</h1>
<!-- エラーメッセージを表示 -->
<p>{$page.error?.message}</p>
svelte

よく使われるパターン

実際のアプリケーションでよく使われるLoad関数のパターンを紹介します。これらの例を参考に、効率的なデータ取得を実装できます。

複数データの同時取得

複数のデータソースから同時にデータを取得することで、パフォーマンスを大幅に改善できます。Promise.allを使って並列処理を実現します。

export const load: PageLoad = async ({ fetch }) => {
  // 並列でデータを取得(効率的)
  // 3つのAPIコールが同時に実行される
  const [posts, categories, tags] = await Promise.all([
    fetch('/api/posts').then(r => r.json()),
    fetch('/api/categories').then(r => r.json()),
    fetch('/api/tags').then(r => r.json())
  ]);
  
  return {
    posts,      // 投稿データ
    categories, // カテゴリ一覧
    tags        // タグ一覧
  };
};
typescript

動的なデータ取得

URLパラメータやユーザーの状態に応じて、異なるデータを取得するパターンです。動的なコンテンツ表示に役立ちます。

export const load: PageLoad = async ({ url, fetch }) => {
  const filter = url.searchParams.get('filter');
  
  // 条件に応じて異なるデータを取得
  // ?filter=active のようなクエリパラメータをチェック
  const data = filter
    ? await fetch(`/api/items?filter=${filter}`).then(r => r.json())
    : await fetch('/api/items').then(r => r.json());
  
  return {
    items: data  // フィルタリングされたデータまたは全データ
  };
};
typescript

ベストプラクティス

Load関数を使う際の推奨事項です。これらのベストプラクティスに従うことで、保守性が高くパフォーマントなコードを書けます。

  1. エラーハンドリング

    • 適切なHTTPステータスコードを返す
    • ユーザーフレンドリーなエラーメッセージ
  2. キャッシュを考慮

    • fetchcacheオプションを適切に設定
    • 適切なキャッシュヘッダーの設定
  3. パフォーマンス最適化

    • 並列処理でデータ取得を高速化
    • 不要なデータ取得を避ける

次のステップ

Last update at: 2025/09/15 08:20:57