12k
All articles

Svelteでコンポーネントを遅延ロードする方法

動的インポートと条件付きレンダリングを使い、SvelteKitやViteベースのプロジェクトで初期バンドルを軽量に保つSvelteコンポーネントの遅延ロード方法を解説する。

OpenReplay Team
OpenReplay Team
Svelteでコンポーネントを遅延ロードする方法

Svelteアプリはデフォルトで高速ですが、リッチテキストエディタ、チャートライブラリ、または複雑なダッシュボードウィジェットを初期JavaScriptペイロードにバンドルしている場合、ユーザーは使用しない可能性のあるコードをダウンロードしています。Svelteのコンポーネントレベルの遅延ロードは、これらの重いインポートを実際に必要になるまで延期することで、この問題を解決します。

Reactとは異なり、Svelteには組み込みのlazy()ヘルパーがありません。代わりに、遅延ロードはJavaScriptのネイティブなimport()関数と条件付きレンダリングを直接組み合わせて使用します。より手動的ですが、より柔軟性があります。

重要なポイント

  • Svelteには組み込みのlazy()ヘルパーがないため、遅延ロードはJavaScriptのネイティブなimport()と条件付きレンダリングを使用します
  • SvelteKitはルートレベルのコード分割を自動的に処理しますが、単一ページ内の重いウィジェットにはコンポーネントレベルの遅延ロードが依然として必要です
  • Viteは設定不要で動的インポートを個別のチャンクに分割します
  • 3つのコアパターンでほとんどのユースケースをカバーできます:{#await}を使用したオンデマンドロード、ホバー時のプリロード、ブラウザがアイドル状態になるまで延期

SvelteKitでコンポーネントレベルの遅延ロードが依然として重要な理由

SvelteKitはすでにルートレベルのコード分割を自動的に処理しています。各ルートは独自のチャンクを取得するため、ページ間を移動しても初期バンドルが肥大化しません。しかし、単一ページ内では、.svelteファイルの先頭でインポートしたすべてのものが一緒にバンドルされ、最初にロードされます。

ここでコンポーネントレベルの遅延ロードが価値を持ちます。ページに重いチャートコンポーネント、ビデオプレーヤー、またはユーザーの操作後にのみ表示されるモーダルが含まれている場合、ページ到着時にそのコードをロードする理由はありません。

SvelteKitはViteでビルドされ、動的インポートをネイティブに処理します。Viteがimport('./HeavyChart.svelte')を見ると、自動的にそのモジュールを個別のチャンクに分割します。追加の設定は不要です。

Svelteコンポーネントを遅延ロードする方法:コアパターン

{#await}を使用した基本的な遅延ロード

最もシンプルなアプローチは、テンプレート内でSvelteの{#await}ブロックを直接使用します:

<!-- src/routes/+page.svelte -->
<script>
  let showChart = false;
  let chartData = [1, 2, 3];
</script>

<button onclick={() => showChart = true}>Load Chart</button>

{#if showChart}
  {#await import('$lib/components/HeavyChart.svelte')}
    <p>Loading chart...</p>
  {:then Chart}
    <Chart.default data={chartData} />
  {:catch error}
    <p>Failed to load chart: {error.message}</p>
  {/await}
{/if}

これはSvelte 4とSvelte 5の両方で動作します。{:catch}ブロックは重要です — ネットワーク障害は発生するものであり、サイレントエラーはデバッグを困難にします。Svelte 4では、動的にコンポーネントを切り替える場合、通常<svelte:component this={Component}>を使用します。モダンなSvelteでは、コンポーネント参照を変更することで直接再レンダリングをトリガーすることもできます。

ブラウザは最初のインポート後にモジュールをキャッシュします。同じコンポーネントの後続のレンダリングでは、新しいネットワークリクエストはトリガーされません。

より速い体感パフォーマンスのためのホバー時のロード

一般的なパターンは、ユーザーが意図を示したとき — トリガー要素にホバーしたときにロードを開始することです:

<!-- src/routes/+page.svelte -->
<script lang="ts">
  import type { Component } from 'svelte';

  let HeavyWidget: Component<{ message: string }> | null = $state(null);

  async function loadWidget() {
    if (!HeavyWidget) {
      const module = await import('$lib/components/HeavyWidget.svelte');
      HeavyWidget = module.default;
    }
  }
</script>

<div onmouseenter={loadWidget}>
  <p>Hover to preload the widget</p>
</div>

{#if HeavyWidget}
  <HeavyWidget message="Ready!" />
{/if}

これはツールチップ、ポップオーバー、サイドバーに適しています。コンポーネントはユーザーがクリックする前にロードを開始するため、ユーザーが操作する頃にはすでにキャッシュされていることが多いです。

ブラウザがアイドル状態のときにロード

ページを改善するが即座に必要ではない非クリティカルなコンポーネントには、requestIdleCallbackを使用します:

<script lang="ts">
  import { onMount } from 'svelte';
  import type { Component } from 'svelte';

  let FeedbackWidget: Component | null = $state(null);

  onMount(() => {
    const load = () =>
      import('$lib/components/FeedbackWidget.svelte').then(
        (m) => (FeedbackWidget = m.default)
      );

    if ('requestIdleCallback' in window) {
      requestIdleCallback(load);
    } else {
      setTimeout(load, 300); // Safariのフォールバック
    }
  });
</script>

{#if FeedbackWidget}
  <FeedbackWidget />
{/if}

SafariのrequestIdleCallbackサポートは歴史的に一貫性がないため、setTimeoutフォールバックが推奨されます。

遅延ロードすべきでない場合

すべてのコンポーネントが遅延ロードの恩恵を受けるわけではありません。以下の場合は避けてください:

  • ファーストビューのUI — ナビゲーション、ヒーローセクション、主要コンテンツ
  • 小さなコンポーネント — 非同期のオーバーヘッドが節約分を上回る
  • マウント時に即座に必要なコンポーネント — ロードのフラッシュがUXを低下させる

過度の分割は多くの小さな非同期チャンクを作成します。Viteのようなモダンなバンドラーはこれを効率的に処理しますが、それでも収穫逓減のポイントがあります。

まとめ

Svelteコンポーネントの遅延ロードは一つのことに集約されます:静的インポートの代わりにimport()を使用し、結果を条件付きでレンダリングすることです。SvelteKitのViteベースのビルドは、コード分割を自動的に処理します。上記の3つのパターン — オンデマンド、ホバー時、アイドル時 — は、ほとんどの実際のシナリオをカバーします。ユーザーが実際にコンポーネントを必要とするタイミングに合わせてトリガーを選択し、エラー処理を追加すれば、初期バンドルは軽量に保たれます。

よくある質問

遅延ロードはSvelte 4でも動作しますか、それともSvelte 5のみですか?

動的インポートは両方のバージョンで動作します。Svelte 4では、通常、ロードされたコンポーネントをthis属性を持つsvelte:componentを使用してレンダリングします。Svelte 5では、解決されたコンポーネントをテンプレート内のタグとして直接使用できます。基礎となるインポートメカニズムは両方のケースで同じです。

SvelteKitのサーバーサイドレンダリング中にコンポーネントを遅延ロードできますか?

Node.jsが動的インポートをサポートしているため、SSR中にも動的インポートは実行されます。ただし、遅延ロードは主にブラウザの初期JavaScriptペイロードを削減することを目的としたクライアントサイドの最適化です。コンポーネントがSEOやファーストペイントの理由でサーバー上でレンダリングされる必要がある場合は、静的インポートがより良い選択です。

どのコンポーネントが遅延ロードする価値があるかをどのように判断しますか?

ビルド出力を確認するか、バンドルアナライザーを使用して大きなチャンクを特定してください。チャートレンダラー、リッチテキストエディタ、マップウィジェットなどの重いサードパーティライブラリを取り込むコンポーネントは強力な候補です。コンポーネントが数キロバイト未満しか追加しない場合、追加のネットワークリクエストのオーバーヘッドが節約分を上回る可能性があります。

遅延ロードされたコンポーネントはレンダリングされるたびにローディング状態がフラッシュしますか?

いいえ。ブラウザは最初の動的インポートが解決された後、モジュールをキャッシュします。後続のレンダリングでは、キャッシュされたモジュールが即座に返されるため、ローディング状態は初回のフェッチ時にのみ表示されます。また、ホバー時やアイドル時にモジュールをプリロードして、可視的な遅延を完全に排除することもできます。

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.