SvelteKitのストリーミング(遅延ロード)を試した話

SvelteKitでは、load 関数から Promise をそのまま返すことで、データの一部を後から流し込むストリーミングが実現できます。重いクエリが完了するまでページ全体を待たせずに、段階的に表示できるのがメリットです。


基本的な仕組み

通常の load 関数はすべてのデータが揃ってからページを返しますが、Promise をそのまま返すとSvelteKitが先にHTMLを送信し、後からデータを流し込みます。

export const load = async () => {
  // awaitする → すぐ表示される
  const fast = await fetchFastData();

  // awaitしない → Promiseのまま返す → 後から流し込まれる
  const slow = fetchSlowData();

  return { fast, slow };
};

Svelte側では {#await} ブロックで受け取ります。

<!-- すぐ表示 -->
<p>{data.fast}</p>

<!-- データが来るまでローディング表示 -->
{#await data.slow}
  <p>読み込み中...</p>
{:then result}
  <p>{result}</p>
{:catch error}
  <p>エラー: {error.message}</p>
{/await}

実装例

+page.server.ts

export const load = async () => {
  const slow = new Promise<string[]>(resolve => {
    setTimeout(() => resolve(['記事A', '記事B', '記事C']), 2000);
  });

  return {
    count: 42,     // すぐ返るデータ
    posts: slow    // 2秒後に返るデータ(Promiseのまま)
  };
};

+page.svelte

<script lang="ts">
  let { data } = $props();
</script>

<h1>ストリーミングデモ</h1>

<!-- すぐ表示される -->
<p>記事数: {data.count} 件</p>

<!-- 2秒後に切り替わる -->
{#await data.posts}
  <p>記事一覧を読み込み中...</p>
{:then posts}
  <ul>
    {#each posts as post}
      <li>{post}</li>
    {/each}
  </ul>
{:catch error}
  <p style="color: red">エラー: {error.message}</p>
{/await}

npm run dev(Vite)で確認すると、「記事数: 42 件」が即座に表示され、2秒後に「読み込み中…」が記事一覧に切り替わります。


{#await} の3つのブロック

ブロック タイミング 用途
{#await promise} Promiseが解決する前 ローディング表示
{:then value} Promiseが解決したとき データ表示
{:catch error} Promiseがrejectしたとき エラー表示

ローディング表示が不要な場合は省略できます。

{#await data.posts then posts}
  {#each posts as post}
    <li>{post}</li>
  {/each}
{/await}

wrangler dev での注意点

npx wrangler dev ではストリーミングレスポンスがバッファリングされるため、「読み込み中…」の状態が表示されません。データが揃ってからまとめてレスポンスが返ってきます。

環境 ストリーミング
npm run dev(Vite) ✅ 動作する
npx wrangler dev ❌ バッファリングされる
本番Cloudflare ✅ 動作する

ストリーミングの動作確認は npm run dev で行い、本番はCloudflareにデプロイして確認するのが現実的です。


まとめ

  • load 関数で Promise をそのまま返すとストリーミングになる
  • Svelte側は {#await} ブロックでローディング・完了・エラーを切り分ける
  • 重いDBクエリをストリーミングにすることで、ページの初期表示を速くできる
  • wrangler dev ではバッファリングされるため、動作確認は npm run dev か本番環境で行う
← トップページに戻る