Next.js や Nuxt などのSSR対応フレームワークと同様に、SvelteKit もデータの読み込みのための標準の方法を備えています(SSRのハイドレーションをうまくやるためですね)。
SvelteKit はこのデータローディングの面でもファイルベースのルーティングを用いていて、各ルートの +page.ts
, +layout.ts
, +page.server.ts
, +layout.server.ts
のファイルで、データ取得処理を load()
関数として記述することで、ページコンポーネントやレイアウトコンポーネントにデータを供給できます。SSRのための裏方の作業も勝手にやってくれます。
...というのは、皆さんご存知だとして、ここではもう少し細かい話を整理してみます。
公式ドキュメントは以下にあります:
+page.ts
と +page.server.ts
の使い分け
基礎的ですが、一応触れておきます。
Universal vs server: https://kit.svelte.dev/docs/load#universal-vs-server
-
+page.ts
と+layout.ts
には、ユニバーサルな(=サーバ上でもブラウザ上でも実行できる)データ取得処理を記述します。サーバサイドレンダリング時にはサーバで実行され、ブラウザでのページ遷移時などにはブラウザで実行されます。ユニバーサルな処理はこちらに書くべきです。 - 一方で
+page.server.ts
と+layout.server.ts
は常にサーバ上で実行されます。必ずサーバ上で実行されなければならない処理はこちらに記述します。
「Provided fetch
function を使え」
Load関数内では、ネイティブの fetch
関数ではなく、SvelteKit が提供する fetch
関数を使います。 load 関数の引数として渡される fetch
関数を受け取って使います。
export const load: PageLoad = async ({ fetch, params }) => {
const res = await fetch(`/api/items/${params.id}`);
const item = await res.json();
return { item };
};
この特別な fetch には SSR を支援するための工夫がなされています:
- URLの invalidation に対応する(後述)
- SvelteKitが受けた Cookie と Authorization ヘッダが fetch 先にも自動で転送される(APIに認証情報を渡すのに便利)
- URLとして相対URLが使える(ユニバーサルな記述をするのに便利)
- SSRのハイドレーションにおいて、サーバでfetchした内容もHTMLに焼き込まれて、ブラウザ側でも同じ内容が取得される。これにより無駄なリクエストがサーバとクライアントの両方で走らない。
- などなど。詳しくは https://kit.svelte.dev/docs/load#making-fetch-requests
load 関数の再実行
Load関数は、URLの変化などに応じて、必要な Load 関数だけが自動で再実行される仕組みになっています(SvelteKit がこれらの変化を追跡する機能を備えています)。詳細はドキュメントを参照してください。 https://kit.svelte.dev/docs/load#rerunning-load-functions
手動での invalidation
しかしながら、Load関数のなかで取得した内容を、ページ遷移などをせずに再読み込みさせたい場面もあります。その場合は invalidate
関数が使えます。 https://kit.svelte.dev/docs/load#rerunning-load-functions-manual-invalidation
fetch したURLを指定して invalidate するのが基本的な使い方です。そのURLに依存しているLoad関数がすべて再実行されます。
invalidate('https://api.example.com/random-number');
invalidate('app:random'); // カスタムの依存関係も作れる → depends を参照
invalidate((url) => url.href.includes('random-number'));
invalidateAll();
各Load関数間の data の流れ
様々な load 関数がどのような流れで働くかは、少し分りづらいところがあるように思います。
各 load 関数の間での data の流れについて、いくつかの要点を整理してみます:
-
+layout.server.ts
,+layout.ts
で取得したデータは、その配下(子レイアウトや子ページ)にあるすべての+layout.svelte
と+page.svelte
でも参照できます。この振る舞いは重要かもしれません。- 同じプロパティ名で衝突した場合は下位の load 関数によるものが優先される、とされています。勝手にオブジェクトの子がマージされたりはしません。注意。
-
+layout.server.ts
で取得したデータは対応する+layout.ts
で参照できます。同様に、+page.server.ts
で取得したデータは対応する+page.ts
で参照できます。 -
parent()
— Load関数でawait parent()
すると、これらの制限を超えて、親の+layout.ts
や+layout.server.ts
の data を待機して取得できます。ただしデータ取得の並列性を阻害して待機することになるn、極力使用を避けるように注意されています。 - (認証などの目的で)すべてのリクエストをフックする
hooks.server.ts
を使う場合にhooks.server.ts
で得られたデータを+(layout|page).server.ts
にも送りたい場合は、リクエストローカルなevent.locals
を介して送ることができます。
適当な図にすると、以下のようになるでしょうか(parent()
は除外):