こんにちは。よっしーです(^^)
今日は、SvelteKitでのデータ読み込みについて解説しています。
背景
SvelteKitでのデータ読み込みについて調査する機会がありましたので、その時の内容を備忘として記事に残しました。
SvelteKitでのデータ読み込み
+page.svelte コンポーネント (およびそれに含まれる +layout.svelte コンポーネント) をレンダリングする前に、多くの場合、データを取得する必要があります。これは、ロード関数を定義することによって行われます。
リダイレクト
ユーザーをリダイレクトするには、@sveltejs/kit のリダイレクト ヘルパーを使用して、3xx ステータス コードとともにリダイレクト先の場所を指定します。error(…) と同様に、redirect(…) を呼び出すと例外がスローされるため、ヘルパー関数内から実行を簡単に停止できます。
// src/routes/user/+layout.server.js
import { redirect } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function load({ locals }) {
if (!locals.user) {
redirect(307, '/login');
}
}
リダイレクトによってすぐに catch ステートメントがトリガーされるため、try {…} ブロック内で redirect() を使用しないでください。
ブラウザーでは、$app.navigation から goto を使用して、ロード関数の外側にプログラム的に移動することもできます。
ストリーミング
サーバー負荷を使用する場合、Promise は解決時にブラウザにストリーミングされます。これは、すべてのデータが利用可能になる前にページのレンダリングを開始できるため、低速で必須ではないデータがある場合に便利です。
// src/routes/blog/[slug]/+page.server.js
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
return {
// make sure the `await` happens at the end, otherwise we
// can't start loading comments until we've loaded the post
comments: loadComments(params.slug),
post: await loadPost(params.slug)
};
}
これは、次のようなスケルトンの読み込み状態を作成するのに役立ちます。
src/routes/blog/[slug]/+page.svelte
<script>
/** @type {import('./$types').PageData} */
export let data;
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#await data.comments}
Loading comments...
{:then comments}
{#each comments as comment}
<p>{comment.content}</p>
{/each}
{:catch error}
<p>error loading comments: {error.message}</p>
{/await}
データをストリーミングする場合、Promise の拒否を正しく処理するように注意してください。具体的には、遅延ロードされた Promise がレンダリングの開始前 (その時点でキャッチされます) に失敗し、何らかの方法でエラーを処理していない場合、サーバーは「未処理の Promise 拒否」エラーでクラッシュする可能性があります。SvelteKit の fetch を load 関数で直接使用すると、SvelteKit がこのケースを処理します。他の Promise の場合は、処理済みとしてマークするために、Promise に noop-catch を添付するだけで十分です。
// src/routes/+page.server.js
/** @type {import('./$types').PageServerLoad} */
export function load({ fetch }) {
const ok_manual = Promise.reject();
ok_manual.catch(() => {});
return {
ok_manual,
ok_fetch: fetch('/fetch/that/could/fail'),
dangerous_unhandled: Promise.reject()
};
}
AWS Lambda や Firebase などのストリーミングをサポートしていないプラットフォームでは、応答はバッファリングされます。つまり、すべての Promise が解決された場合にのみページがレンダリングされます。プロキシ (NGINX など) を使用している場合は、プロキシ サーバーからの応答がバッファリングされないようにしてください。
ストリーミング データは、JavaScript が有効になっている場合にのみ機能します。ページがサーバーでレンダリングされる場合は、ユニバーサル ロード関数から promise を返すことは避けてください。これは、promise がストリーミングされないためです。代わりに、関数がブラウザーで再実行されると、promise が再作成されます。
応答のストリーミングが開始されると、応答のヘッダーとステータス コードを変更することはできないため、ストリーミングされた Promise 内で Headers を設定したり、リダイレクトをスローしたりすることはできません。
並列ロード
ページをレンダリング (またはページに移動) する際、SvelteKit はすべてのロード関数を同時に実行し、リクエストのウォーターフォールを回避します。クライアント側のナビゲーション中、複数のサーバー ロード関数を呼び出した結果が 1 つの応答にグループ化されます。すべてのロード関数が返されると、ページがレンダリングされます。
おわりに
今日は、 SvelteKitでのデータ読み込みについて解説しました。
何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。
それでは、また明日お会いしましょう(^^)
コメント