データの読み込み
+page.svelteコンポーネント(およびその親となる+layout.svelteコンポーネント)がレンダリングされる前に、多くの場合、何らかのデータが必要になります。これはload関数を定義することで行います。
ページデータ
+page.svelteファイルは、load関数をエクスポートする兄弟の+page.jsを持つことができ、その戻り値はdataプロップを通じてページで利用できます。
/** @type {import('./$types').PageLoad} */
export function function load({ params }: {
params: any;
}): {
post: {
title: string;
content: string;
};
}
load({ params: anyparams }) {
return {
post: {
title: string;
content: string;
}
post: {
title: stringtitle: `Title for ${params: anyparams.slug} goes here`,
content: stringcontent: `Content for ${params: anyparams.slug} goes here`
}
};
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = ({ params: Record<string, any>The parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object
params }) => {
return {
post: {
title: string;
content: string;
}
post: {
title: stringtitle: `Title for ${params: Record<string, any>The parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug} goes here`,
content: stringcontent: `Content for ${params: Record<string, any>The parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug} goes here`
}
};
};<script>
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div><script lang="ts">
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>レガシーモード
Svelte 4では、代わりに
export let dataを使用します。
生成された$typesモジュールのおかげで、完全に型安全性が確保されます。
+page.jsファイル内のload関数は、サーバーとブラウザの両方で実行されます(export const ssr = falseと組み合わせた場合を除く。その場合はブラウザでのみ実行されます)。load関数が(たとえば、プライベート環境変数を使用したり、データベースにアクセスしたりするため)常にサーバーで実行される必要がある場合は、代わりに+page.server.jsに入ります。
データベースからデータを取得し、サーバーでのみ実行する、より現実的なブログ記事のload関数は、次のようになります。
import * as module "$lib/server/database"db from '$lib/server/database';
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>load({ params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params }) {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug)
};
}import * as module "$lib/server/database"db from '$lib/server/database';
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageServerLoad } from './$types';
export const const load: PageServerLoadload: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageServerLoad = async ({ params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params }) => {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug)
};
};サーバーのload関数は追加の引数にアクセスできるため、型がPageLoadからPageServerLoadに変更されたことに注意してください。+page.jsと+page.server.jsをいつ使用するかを理解するには、ユニバーサル vs サーバーを参照してください。
レイアウトデータ
+layout.svelteファイルも、+layout.jsまたは+layout.server.jsを介してデータを読み込むことができます。
import * as module "$lib/server/database"db from '$lib/server/database';
/** @type {import('./$types').LayoutServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>load() {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
}import * as module "$lib/server/database"db from '$lib/server/database';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad } from './$types';
export const const load: LayoutServerLoadload: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad = async () => {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
};<script>
/** @type {{ data: import('./$types').LayoutData, children: Snippet }} */
let { data, children } = $props();
</script>
<main>
<!-- +page.svelte is `@render`ed here -->
{@render children()}
</main>
<aside>
<h2>More posts</h2>
<ul>
{#each data.posts as post}
<li>
<a href="/blog/{post.slug}">
{post.title}
</a>
</li>
{/each}
</ul>
</aside><script lang="ts">
import type { LayoutData } from './$types';
let { data, children }: { data: LayoutData, children: Snippet } = $props();
</script>
<main>
<!-- +page.svelte is `@render`ed here -->
{@render children()}
</main>
<aside>
<h2>More posts</h2>
<ul>
{#each data.posts as post}
<li>
<a href="/blog/{post.slug}">
{post.title}
</a>
</li>
{/each}
</ul>
</aside>レイアウトのload関数から返されたデータは、子+layout.svelteコンポーネントと+page.svelteコンポーネント、およびそれが「属する」レイアウトでも利用できます。
<script>
import { page } from '$app/stores';
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
// we can access `data.posts` because it's returned from
// the parent layout `load` function
let index = $derived(data.posts.findIndex(post => post.slug === $page.params.slug));
let next = $derived(data.posts[index + 1]);
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#if next}
<p>Next post: <a href="/blog/{next.slug}">{next.title}</a></p>
{/if}<script lang="ts">
import { page } from '$app/stores';
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
// we can access `data.posts` because it's returned from
// the parent layout `load` function
let index = $derived(data.posts.findIndex(post => post.slug === $page.params.slug));
let next = $derived(data.posts[index + 1]);
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#if next}
<p>Next post: <a href="/blog/{next.slug}">{next.title}</a></p>
{/if}複数の
load関数が同じキーでデータを返す場合、最後のものが「優先」されます。つまり、レイアウトのloadが{ a: 1, b: 2 }を返し、ページのloadが{ b: 3, c: 4 }を返すと、結果は{ a: 1, b: 3, c: 4 }になります。
$page.data
+page.svelteコンポーネントと、その上の各+layout.svelteコンポーネントは、自身のデータと親からのすべてのデータにアクセスできます。
場合によっては、親レイアウトがページデータや子レイアウトからのデータにアクセスする必要があるなど、逆のケースが必要になる場合があります。たとえば、ルートレイアウトは、+page.jsまたは+page.server.jsのload関数から返されたtitleプロパティにアクセスする必要がある場合があります。これは$page.dataを使用することで実現できます。
<script>
import { page } from '$app/stores';
</script>
<svelte:head>
<title>{$page.data.title}</title>
</svelte:head>$page.dataの型情報は、App.PageDataによって提供されます。
ユニバーサル vs サーバー
これまで見てきたように、load関数には2つのタイプがあります。
+page.jsと+layout.jsファイルは、サーバーとブラウザの両方で実行されるユニバーサルload関数をエクスポートします。+page.server.jsと+layout.server.jsファイルは、サーバー側でのみ実行されるサーバーload関数をエクスポートします。
概念的には同じものですが、注意すべき重要な違いがいくつかあります。
どのload関数がいつ実行されるか?
サーバーのload関数は常にサーバーで実行されます。
デフォルトでは、ユニバーサルのload関数は、ユーザーが最初にページにアクセスしたときにSSR中にサーバーで実行されます。その後、fetchリクエストからのレスポンスを再利用して、ハイドレーション中に再度実行されます。以降のユニバーサルload関数の呼び出しはすべてブラウザで発生します。ページオプションを通じて動作をカスタマイズできます。サーバーサイドレンダリングを無効にすると、SPAになり、ユニバーサルのload関数は常にクライアントで実行されます。
ルートにユニバーサルとサーバーのload関数の両方が含まれている場合、サーバーのloadが最初に実行されます。
load関数は、ページをプリレンダリングしない限り、実行時に呼び出されます。その場合、ビルド時に呼び出されます。
入力
ユニバーサルとサーバーの両方のload関数は、リクエスト(params、route、url)とさまざまな関数(fetch、setHeaders、parent、depends、untrack)を記述するプロパティにアクセスできます。これらについては、次のセクションで説明します。
サーバーのload関数は、RequestEventからclientAddress、cookies、locals、platform、requestを継承するServerLoadEventで呼び出されます。
ユニバーサルのload関数は、dataプロパティを持つLoadEventで呼び出されます。+page.jsと+page.server.js(または+layout.jsと+layout.server.js)の両方にload関数がある場合、サーバーのload関数の戻り値は、ユニバーサルのload関数の引数のdataプロパティになります。
出力
ユニバーサルのload関数は、カスタムクラスやコンポーネントコンストラクターなどの任意の値を含むオブジェクトを返すことができます。
サーバーのload関数は、devalueでシリアライズできるデータを返す必要があります。これは、JSONとして表現できるものに加えて、BigInt、Date、Map、Set、RegExp、または繰り返し/循環参照のようなものです。そうすることで、ネットワーク経由で転送できます。データにはPromiseを含めることができ、その場合、ブラウザにストリーミングされます。
どちらをいつ使用するか
データベースやファイルシステムから直接データにアクセスする必要がある場合、またはプライベートな環境変数を使用する必要がある場合は、サーバーのload関数が便利です。
外部APIからfetchする必要があり、プライベートな資格情報を必要としない場合、SvelteKitはサーバー経由ではなくAPIから直接データを取得できるため、ユニバーサルのload関数が役立ちます。シリアライズできないもの(Svelteコンポーネントコンストラクターなど)を返す必要がある場合にも役立ちます。
まれに、両方を一緒に使用する必要がある場合があります。たとえば、サーバーからのデータで初期化されたカスタムクラスのインスタンスを返す必要がある場合などです。両方を使用する場合、サーバーのloadの戻り値はページに直接渡されるのではなく、ユニバーサルのload関数(dataプロパティとして)に渡されます。
/** @type {import('./$types').PageServerLoad} */
export async function function load(): Promise<{
serverMessage: string;
}>
load() {
return {
serverMessage: stringserverMessage: 'hello from server load function'
};
}import type { type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoadload: type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async () => {
return {
serverMessage: stringserverMessage: 'hello from server load function'
};
};/** @type {import('./$types').PageLoad} */
export async function function load({ data }: {
data: any;
}): Promise<{
serverMessage: any;
universalMessage: string;
}>
load({ data: anydata }) {
return {
serverMessage: anyserverMessage: data: anydata.serverMessage,
universalMessage: stringuniversalMessage: 'hello from universal load function'
};
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ data: Record<string, any> | nullContains the data returned by the route’s server load function (in +layout.server.js or +page.server.js), if any.
data }) => {
return {
serverMessage: anyserverMessage: data: Record<string, any> | nullContains the data returned by the route’s server load function (in +layout.server.js or +page.server.js), if any.
data.serverMessage,
universalMessage: stringuniversalMessage: 'hello from universal load function'
};
};URLデータの使用
多くの場合、load関数はURLに何らかの形で依存します。このために、load関数はurl、route、paramsを提供します。
url
URLのインスタンス。origin、hostname、pathname、およびsearchParams(解析済みのクエリ文字列をURLSearchParamsオブジェクトとして含む)のようなプロパティを含みます。サーバーでは利用できないため、load中にurl.hashにアクセスすることはできません。
一部の環境では、これはサーバーサイドレンダリング中のリクエストヘッダーから派生します。たとえば、adapter-nodeを使用している場合は、URLが正しくなるようにアダプターを構成する必要がある場合があります。
route
src/routesからの相対的な、現在のルートディレクトリの名前が含まれます。
/** @type {import('./$types').PageLoad} */
export function function load({ route }: {
route: any;
}): void
load({ route: anyroute }) {
var console: ConsoleThe console module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
- A global
console instance configured to write to process.stdout and
process.stderr. The global console can be used without calling require('console').
Warning: The global console object’s methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)Prints to stdout with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
See util.format() for more information.
log(route: anyroute.id); // '/a/[b]/[...c]'
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = ({ route: {
id: string | null;
}
Info about the current route
route }) => {
var console: ConsoleThe console module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
- A global
console instance configured to write to process.stdout and
process.stderr. The global console can be used without calling require('console').
Warning: The global console object’s methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O for
more information.
Example using the global console:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console class:
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)Prints to stdout with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()).
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
See util.format() for more information.
log(route: {
id: string | null;
}
Info about the current route
route.id: string | nullThe ID of the current route - e.g. for src/routes/blog/[slug], it would be /blog/[slug]
id); // '/a/[b]/[...c]'
};params
paramsは、url.pathnameとroute.idから派生します。
route.idが/a/[b]/[...c]で、url.pathnameが/a/x/y/zの場合、paramsオブジェクトは次のようになります。
{
"b": "x",
"c": "y/z"
}fetchリクエストの実行
外部APIまたは+server.jsハンドラーからデータを取得するには、提供されているfetch関数を使用できます。これは、追加機能がいくつかあることを除けば、ネイティブのfetch Web APIとまったく同じように動作します。
- ページリクエストの
cookieおよびauthorizationヘッダーを継承するため、サーバーで資格情報付きのリクエストを行うために使用できます。 - サーバーで相対リクエストを行うことができます(通常、
fetchはサーバーコンテキストで使用する場合にオリジン付きのURLを必要とします)。 - 内部リクエスト(例えば、
+server.jsルートへのリクエスト)は、サーバー上で実行されている場合、HTTP呼び出しのオーバーヘッドなしに、直接ハンドラー関数に送られます。 - サーバーサイドレンダリング中、レスポンスはキャプチャされ、
Responseオブジェクトのtext、json、arrayBufferメソッドにフックすることで、レンダリングされたHTMLにインライン化されます。ヘッダーは、filterSerializedResponseHeaders経由で明示的に含められない限り、シリアライズされないことに注意してください。 - ハイドレーション中、レスポンスはHTMLから読み込まれ、一貫性が保証され、追加のネットワークリクエストを防ぎます。ブラウザの
fetchをloadのfetchの代わりに使用したときにブラウザのコンソールで警告が表示された場合、これがその理由です。
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, params }: {
fetch: any;
params: any;
}): Promise<{
item: any;
}>
load({ fetch: anyfetch, params: anyparams }) {
const const res: anyres = await fetch: anyfetch(`/api/items/${params: anyparams.id}`);
const const item: anyitem = await const res: anyres.json();
return { item: anyitem };
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch is equivalent to the native fetch web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie and authorization headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text and json methods of the Response object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch, params: Record<string, any>The parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object
params }) => {
const const res: Responseres = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)fetch(`/api/items/${params: Record<string, any>The parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object
params.id}`);
const const item: anyitem = await const res: Responseres.Body.json(): Promise<any>json();
return { item: anyitem };
};クッキー
サーバーのload関数は、cookiesを取得および設定できます。
import * as module "$lib/server/database"db from '$lib/server/database';
/** @type {import('./$types').LayoutServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>load({ cookies: CookiesGet or set cookies related to the current request
cookies }) {
const const sessionid: string | undefinedsessionid = cookies: CookiesGet or set cookies related to the current request
cookies.Cookies.get(name: string, opts?: CookieParseOptions): string | undefinedGets a cookie that was previously set with cookies.set, or from the request headers.
get('sessionid');
return {
user: {
name: string;
avatar: string;
}
user: await module "$lib/server/database"db.function getUser(sessionid: string | undefined): Promise<{
name: string;
avatar: string;
}>
getUser(const sessionid: string | undefinedsessionid)
};
}import * as module "$lib/server/database"db from '$lib/server/database';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad } from './$types';
export const const load: LayoutServerLoadload: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad = async ({ cookies: CookiesGet or set cookies related to the current request
cookies }) => {
const const sessionid: string | undefinedsessionid = cookies: CookiesGet or set cookies related to the current request
cookies.Cookies.get(name: string, opts?: CookieParseOptions): string | undefinedGets a cookie that was previously set with cookies.set, or from the request headers.
get('sessionid');
return {
user: {
name: string;
avatar: string;
}
user: await module "$lib/server/database"db.function getUser(sessionid: string | undefined): Promise<{
name: string;
avatar: string;
}>
getUser(const sessionid: string | undefinedsessionid)
};
};クッキーは、ターゲットホストがSvelteKitアプリケーションと同じか、より具体的なサブドメインである場合にのみ、提供されたfetch関数を介して渡されます。
例えば、SvelteKitがmy.domain.comを提供している場合、
- domain.com はクッキーを受信しません
- my.domain.com はクッキーを受信します
- api.domain.com はクッキーを受信しません
- sub.my.domain.com はクッキーを受信します
SvelteKitはどのドメインにどのクッキーが属するかを知らない(ブラウザはこの情報を渡さない)ため、他のクッキーはcredentials: 'include'が設定されていても渡されず、転送することは安全ではありません。この問題を回避するには、handleFetchフックを使用してください。
ヘッダー
サーバーとユニバーサルのload関数の両方で、setHeaders関数にアクセスできます。この関数は、サーバーで実行されている場合にレスポンスのヘッダーを設定できます。(ブラウザで実行されている場合、setHeadersは効果がありません。)例えば、ページをキャッシュしたい場合に便利です。
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, setHeaders }: {
fetch: any;
setHeaders: any;
}): Promise<any>
load({ fetch: anyfetch, setHeaders: anysetHeaders }) {
const const url: "https://cms.example.com/products.json"url = `https://cms.example.com/products.json`;
const const response: anyresponse = await fetch: anyfetch(const url: "https://cms.example.com/products.json"url);
// Headers are only set during SSR, caching the page's HTML
// for the same length of time as the underlying data.
setHeaders: anysetHeaders({
age: anyage: const response: anyresponse.headers.get('age'),
'cache-control': const response: anyresponse.headers.get('cache-control')
});
return const response: anyresponse.json();
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch is equivalent to the native fetch web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie and authorization headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text and json methods of the Response object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch, setHeaders: (headers: Record<string, string>) => voidIf you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
src/routes/blog/+pageexport async function load({ fetch, setHeaders }) {
const url = `https://cms.example.com/articles.json`;
const response = await fetch(url);
setHeaders({
age: response.headers.get('age'),
'cache-control': response.headers.get('cache-control')
});
return response.json();
}
Setting the same header multiple times (even in separate load functions) is an error — you can only set a given header once.
You cannot add a set-cookie header with setHeaders — use the cookies API in a server-only load function instead.
setHeaders has no effect when a load function runs in the browser.
setHeaders }) => {
const const url: "https://cms.example.com/products.json"url = `https://cms.example.com/products.json`;
const const response: Responseresponse = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)fetch(const url: "https://cms.example.com/products.json"url);
// Headers are only set during SSR, caching the page's HTML
// for the same length of time as the underlying data.
setHeaders: (headers: Record<string, string>) => voidIf you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
src/routes/blog/+pageexport async function load({ fetch, setHeaders }) {
const url = `https://cms.example.com/articles.json`;
const response = await fetch(url);
setHeaders({
age: response.headers.get('age'),
'cache-control': response.headers.get('cache-control')
});
return response.json();
}
Setting the same header multiple times (even in separate load functions) is an error — you can only set a given header once.
You cannot add a set-cookie header with setHeaders — use the cookies API in a server-only load function instead.
setHeaders has no effect when a load function runs in the browser.
setHeaders({
age: string | nullage: const response: Responseresponse.Response.headers: Headersheaders.Headers.get(name: string): string | nullget('age'),
'cache-control': const response: Responseresponse.Response.headers: Headersheaders.Headers.get(name: string): string | nullget('cache-control')
});
return const response: Responseresponse.Body.json(): Promise<any>json();
};同じヘッダーを複数回(異なるload関数でも)設定するとエラーになります。setHeaders関数を使用して、特定のヘッダーを1回だけ設定できます。setHeadersを使用してset-cookieヘッダーを追加することはできません。代わりに、cookies.set(name, value, options)を使用してください。
親データの使用
load関数が親のload関数からデータにアクセスできると便利な場合があります。これは、await parent()を使用して行うことができます。
/** @type {import('./$types').LayoutLoad} */
export function function load(): {
a: number;
}
load() {
return { a: numbera: 1 };
}import type { type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad } from './$types';
export const const load: LayoutLoadload: type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad = () => {
return { a: numbera: 1 };
};/** @type {import('./$types').LayoutLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
b: any;
}>
load({ parent: anyparent }) {
const { const a: anya } = await parent: anyparent();
return { b: anyb: const a: anya + 1 };
}import type { type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad } from './$types';
export const const load: LayoutLoadload: type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad = async ({ parent: () => Promise<Record<string, any>>await parent() returns data from parent +layout.js load functions.
Implicitly, a missing +layout.js is treated as a ({ data }) => data function, meaning that it will return and forward data from parent +layout.server.js files.
Be careful not to introduce accidental waterfalls when using await parent(). If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) => {
const { const a: anya } = await parent: () => Promise<Record<string, any>>await parent() returns data from parent +layout.js load functions.
Implicitly, a missing +layout.js is treated as a ({ data }) => data function, meaning that it will return and forward data from parent +layout.server.js files.
Be careful not to introduce accidental waterfalls when using await parent(). If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return { b: anyb: const a: anya + 1 };
};/** @type {import('./$types').PageLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
c: any;
}>
load({ parent: anyparent }) {
const { const a: anya, const b: anyb } = await parent: anyparent();
return { c: anyc: const a: anya + const b: anyb };
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ parent: () => Promise<Record<string, any>>await parent() returns data from parent +layout.js load functions.
Implicitly, a missing +layout.js is treated as a ({ data }) => data function, meaning that it will return and forward data from parent +layout.server.js files.
Be careful not to introduce accidental waterfalls when using await parent(). If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) => {
const { const a: anya, const b: anyb } = await parent: () => Promise<Record<string, any>>await parent() returns data from parent +layout.js load functions.
Implicitly, a missing +layout.js is treated as a ({ data }) => data function, meaning that it will return and forward data from parent +layout.server.js files.
Be careful not to introduce accidental waterfalls when using await parent(). If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return { c: anyc: const a: anya + const b: anyb };
};<script>
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
</script>
<!-- renders `1 + 2 = 3` -->
<p>{data.a} + {data.b} = {data.c}</p><script lang="ts">
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
</script>
<!-- renders `1 + 2 = 3` -->
<p>{data.a} + {data.b} = {data.c}</p>
+page.jsのload関数は、直接の親だけでなく、両方のレイアウトload関数からマージされたデータを受け取ることに注意してください。
+page.server.jsと+layout.server.js内では、parentは親の+layout.server.jsファイルからのデータを返します。
+page.jsまたは+layout.jsでは、親の+layout.jsファイルからのデータを返します。ただし、存在しない+layout.jsは({ data }) => data関数として扱われます。つまり、+layout.jsファイルによって「シャドウイング」されていない親の+layout.server.jsファイルからのデータも返されます。
await parent()を使用する際は、ウォーターフォールを導入しないように注意してください。たとえば、ここではgetData(params)はparent()の呼び出し結果に依存していないため、レンダリングの遅延を避けるために最初に呼び出す必要があります。
/** @type {import('./$types').PageLoad} */
export async function function load(event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>load({ params: Record<string, any>The parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object
params, parent: () => Promise<Record<string, any>>await parent() returns data from parent +layout.js load functions.
Implicitly, a missing +layout.js is treated as a ({ data }) => data function, meaning that it will return and forward data from parent +layout.server.js files.
Be careful not to introduce accidental waterfalls when using await parent(). If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) {
const parentData = await parent();
const const data: {
meta: any;
}
data = await function getData(params: Record<string, string>): Promise<{
meta: any;
}>
getData(params: Record<string, any>The parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object
params);
const const parentData: Record<string, any>parentData = await parent: () => Promise<Record<string, any>>await parent() returns data from parent +layout.js load functions.
Implicitly, a missing +layout.js is treated as a ({ data }) => data function, meaning that it will return and forward data from parent +layout.server.js files.
Be careful not to introduce accidental waterfalls when using await parent(). If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return {
...const data: {
meta: any;
}
data,
meta: anymeta: { ...const parentData: Record<string, any>parentData.meta, ...const data: {
meta: any;
}
data.meta: anymeta }
};
}import type { type PageLoad = (event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageLoad = async ({ params: Record<string, any>The parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object
params, parent: () => Promise<Record<string, any>>await parent() returns data from parent +layout.js load functions.
Implicitly, a missing +layout.js is treated as a ({ data }) => data function, meaning that it will return and forward data from parent +layout.server.js files.
Be careful not to introduce accidental waterfalls when using await parent(). If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) => {
const parentData = await parent();
const const data: {
meta: any;
}
data = await function getData(params: Record<string, string>): Promise<{
meta: any;
}>
getData(params: Record<string, any>The parameters of the current page - e.g. for a route like /blog/[slug], a { slug: string } object
params);
const const parentData: Record<string, any>parentData = await parent: () => Promise<Record<string, any>>await parent() returns data from parent +layout.js load functions.
Implicitly, a missing +layout.js is treated as a ({ data }) => data function, meaning that it will return and forward data from parent +layout.server.js files.
Be careful not to introduce accidental waterfalls when using await parent(). If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return {
...const data: {
meta: any;
}
data,
meta: anymeta: { ...const parentData: Record<string, any>parentData.meta, ...const data: {
meta: any;
}
data.meta: anymeta }
};
};エラー
load中にエラーがスローされると、最も近い+error.svelteがレンダリングされます。予期されたエラーの場合は、HTTPステータスコードとオプションのメッセージを指定するために、@sveltejs/kitのerrorヘルパーを使用してください。
import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>load({ locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals }) {
if (!locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
} | undefined
user) {
function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error(401, 'not logged in');
}
if (!locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: booleanisAdmin) {
function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error(403, 'not an admin');
}
}import { function error(status: number, body: App.Error): never (+1 overload)Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error } from '@sveltejs/kit';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad } from './$types';
export const const load: LayoutServerLoadload: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad = ({ locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals }) => {
if (!locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
} | undefined
user) {
function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error(401, 'not logged in');
}
if (!locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: booleanisAdmin) {
function error(status: number, body?: {
message: string;
} extends App.Error ? App.Error | string | undefined : never): never (+1 overload)
Throws an error with a HTTP status code and an optional message.
When called during request handling, this will cause SvelteKit to
return an error response without invoking handleError.
Make sure you’re not catching the thrown error, which would prevent SvelteKit from handling it.
error(403, 'not an admin');
}
};error(...)を呼び出すと例外がスローされるため、ヘルパー関数内からの実行を簡単に停止できます。
予期しないエラーがスローされた場合、SvelteKitはhandleErrorを呼び出し、500内部エラーとして扱います。
SvelteKit 1.xでは、エラーを自分で
throwする必要がありました。
リダイレクト
ユーザーをリダイレクトするには、@sveltejs/kitのredirectヘルパーを使用して、リダイレクト先の場所と3xxステータスコードを指定します。error(...)と同様に、redirect(...)を呼び出すと例外がスローされるため、ヘルパー関数内からの実行を簡単に停止できます。
import { function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
redirect } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>load({ locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals }) {
if (!locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: {
name: string;
} | undefined
user) {
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
redirect(307, '/login');
}
}import { function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
redirect } from '@sveltejs/kit';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad } from './$types';
export const const load: LayoutServerLoadload: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad = ({ locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals }) => {
if (!locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: {
name: string;
} | undefined
user) {
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
redirect(307, '/login');
}
};
try {...}ブロック内でredirect()を使用しないでください。リダイレクトがすぐにcatchステートメントをトリガーするためです。
ブラウザでは、$app.navigationのgotoを使用して、load関数外でプログラム的にナビゲートすることもできます。
SvelteKit 1.xでは、
redirectを自分でthrowする必要がありました。
Promiseを使用したストリーミング
サーバーのloadを使用する場合、Promiseは解決されるとブラウザにストリーミングされます。これは、データがすべて利用可能になる前にページのレンダリングを開始できるため、遅くて重要でないデータがある場合に役立ちます。
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>load({ params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params }) {
return {
// make sure the `await` happens at the end, otherwise we
// can't start loading comments until we've loaded the post
comments: Promise<{
content: string;
}>
comments: const loadComments: (slug: string) => Promise<{
content: string;
}>
loadComments(params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug),
post: {
title: string;
content: string;
}
post: await const loadPost: (slug: string) => Promise<{
title: string;
content: string;
}>
loadPost(params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug)
};
}import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageServerLoad } from './$types';
export const const load: PageServerLoadload: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageServerLoad = async ({ params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params }) => {
return {
// make sure the `await` happens at the end, otherwise we
// can't start loading comments until we've loaded the post
comments: Promise<{
content: string;
}>
comments: const loadComments: (slug: string) => Promise<{
content: string;
}>
loadComments(params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug),
post: {
title: string;
content: string;
}
post: await const loadPost: (slug: string) => Promise<{
title: string;
content: string;
}>
loadPost(params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug)
};
};これは、例えばスケルトンローディング状態を作成するのに役立ちます。
<script>
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
</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}<script lang="ts">
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
</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拒否」エラーでクラッシュする可能性があります。load関数でSvelteKitのfetchを直接使用する場合、SvelteKitがこのケースを処理します。その他のPromiseの場合は、noopのcatchをPromiseにアタッチして、処理済みとしてマークするだけで十分です。
/** @type {import('./$types').PageServerLoad} */
export function function load({ fetch }: {
fetch: any;
}): {
ok_manual: Promise<never>;
ok_fetch: any;
dangerous_unhandled: Promise<never>;
}
load({ fetch: anyfetch }) {
const const ok_manual: Promise<never>ok_manual = var Promise: PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>Creates a new rejected promise for the provided reason.
reject();
const ok_manual: Promise<never>ok_manual.Promise<never>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>Attaches a callback for only the rejection of the Promise.
catch(() => {});
return {
ok_manual: Promise<never>ok_manual,
ok_fetch: anyok_fetch: fetch: anyfetch('/fetch/that/could/fail'),
dangerous_unhandled: Promise<never>dangerous_unhandled: var Promise: PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>Creates a new rejected promise for the provided reason.
reject()
};
}import type { type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoadload: type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch is equivalent to the native fetch web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie and authorization headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text and json methods of the Response object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch }) => {
const const ok_manual: Promise<never>ok_manual = var Promise: PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>Creates a new rejected promise for the provided reason.
reject();
const ok_manual: Promise<never>ok_manual.Promise<never>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>Attaches a callback for only the rejection of the Promise.
catch(() => {});
return {
ok_manual: Promise<never>ok_manual,
ok_fetch: Promise<Response>ok_fetch: fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)fetch('/fetch/that/could/fail'),
dangerous_unhandled: Promise<never>dangerous_unhandled: var Promise: PromiseConstructorRepresents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>Creates a new rejected promise for the provided reason.
reject()
};
};AWS LambdaやFirebaseなどのストリーミングをサポートしていないプラットフォームでは、レスポンスがバッファリングされます。つまり、すべてのPromiseが解決されると、ページがレンダリングされます。プロキシ(例:NGINX)を使用している場合は、プロキシされたサーバーからのレスポンスをバッファリングしないようにしてください。
ストリーミングデータは、JavaScriptが有効になっている場合にのみ機能します。ページがサーバーレンダリングされる場合は、ユニバーサルの
load関数からPromiseを返さないようにする必要があります。これらはストリーミングされず、代わりに、関数がブラウザで再実行されるときにPromiseが再作成されるためです。
レスポンスのストリーミングが開始されると、レスポンスのヘッダーとステータスコードは変更できません。そのため、ストリーミングされたPromise内で
setHeadersを設定したり、リダイレクトをスローしたりすることはできません。
SvelteKit 1.xでは、トップレベルのPromiseは自動的に待機され、ネストされたPromiseのみがストリーミングされました。
並列読み込み
ページをレンダリング(またはナビゲート)するとき、SvelteKitはすべてのload関数を並行して実行し、リクエストのウォーターフォールを回避します。クライアントサイドナビゲーション中、複数のサーバーload関数の呼び出し結果は、単一のレスポンスにグループ化されます。すべてのload関数が戻ると、ページがレンダリングされます。
load関数の再実行
SvelteKitは各load関数の依存関係を追跡して、ナビゲーション中に不必要に再実行しないようにします。
たとえば、次のような一対のload関数があるとします...
import * as module "$lib/server/database"db from '$lib/server/database';
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>load({ params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params }) {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug)
};
}import * as module "$lib/server/database"db from '$lib/server/database';
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageServerLoad } from './$types';
export const const load: PageServerLoadload: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageServerLoad = async ({ params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params }) => {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>The parameters of the current route - e.g. for a route like /blog/[slug], a { slug: string } object
params.slug)
};
};import * as module "$lib/server/database"db from '$lib/server/database';
/** @type {import('./$types').LayoutServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>load() {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
}import * as module "$lib/server/database"db from '$lib/server/database';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad } from './$types';
export const const load: LayoutServerLoadload: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad = async () => {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
};...params.slugが変更されたため、/blog/trying-the-raw-meat-dietから/blog/i-regret-my-choicesに移動すると、+page.server.jsのものが再実行されます。データはまだ有効であるため、+layout.server.jsのものは再実行されません。言い換えれば、db.getPostSummaries()を2回呼び出すことはありません。
await parent()を呼び出すload関数は、親のload関数が再実行された場合にも再実行されます。
依存関係の追跡は、load関数が戻った後には適用されません。たとえば、ネストされたPromise内でparams.xにアクセスしても、params.xが変更されたときに関数が再実行されることはありません。(誤ってこれを行うと、開発中に警告が表示されます。)代わりに、load関数のメイン本文でパラメーターにアクセスしてください。
検索パラメーターは、URLの残りの部分とは独立して追跡されます。たとえば、load関数内でevent.url.searchParams.get("x")にアクセスすると、?x=1から?x=2に移動するときにそのload関数が再実行されますが、?x=1&y=1から?x=1&y=2に移動するときには再実行されません。
依存関係の追跡解除
まれに、依存関係追跡メカニズムから何かを除外したい場合があります。これは、提供されているuntrack関数を使用して行うことができます。
/** @type {import('./$types').PageLoad} */
export async function function load({ untrack, url }: {
untrack: any;
url: any;
}): Promise<{
message: string;
} | undefined>
load({ untrack: anyuntrack, url: anyurl }) {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack: anyuntrack(() => url: anyurl.pathname === '/')) {
return { message: stringmessage: 'Welcome!' };
}
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ untrack: <T>(fn: () => T) => TUse this function to opt out of dependency tracking for everything that is synchronously called within the callback. Example:
src/routes/+page.serverexport async function load({ untrack, url }) {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack(() => url.pathname === '/')) {
return { message: 'Welcome!' };
}
}
untrack, url: URLThe URL of the current page
url }) => {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack: <boolean>(fn: () => boolean) => booleanUse this function to opt out of dependency tracking for everything that is synchronously called within the callback. Example:
src/routes/+page.serverexport async function load({ untrack, url }) {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack(() => url.pathname === '/')) {
return { message: 'Welcome!' };
}
}
untrack(() => url: URLThe URL of the current page
url.URL.pathname: stringpathname === '/')) {
return { message: stringmessage: 'Welcome!' };
}
};手動での無効化
現在のページに適用されるload関数を、invalidate(url)を使用して再実行することもできます。これは、urlに依存するすべてのload関数を再実行します。また、invalidateAll()を使用すると、すべてのload関数が再実行されます。サーバーのload関数は、クライアントに秘密が漏洩するのを防ぐために、フェッチされたurlに自動的に依存することはありません。
load関数は、fetch(url)またはdepends(url)を呼び出すと、urlに依存します。urlは、[a-z]:で始まるカスタム識別子にすることもできます。
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, depends }: {
fetch: any;
depends: any;
}): Promise<{
number: any;
}>
load({ fetch: anyfetch, depends: anydepends }) {
// load reruns when `invalidate('https://api.example.com/random-number')` is called...
const const response: anyresponse = await fetch: anyfetch('https://api.example.com/random-number');
// ...or when `invalidate('app:random')` is called
depends: anydepends('app:random');
return {
number: anynumber: await const response: anyresponse.json()
};
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch is equivalent to the native fetch web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie and authorization headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text and json methods of the Response object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch, depends: (...deps: Array<`${string}:${string}`>) => voidThis function declares that the load function has a dependency on one or more URLs or custom identifiers, which can subsequently be used with invalidate() to cause load to rerun.
Most of the time you won’t need this, as fetch calls depends on your behalf — it’s only necessary if you’re using a custom API client that bypasses fetch.
URLs can be absolute or relative to the page being loaded, and must be encoded.
Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the URI specification.
The following example shows how to use depends to register a dependency on a custom identifier, which is invalidated after a button click, making the load function rerun.
src/routes/+pagelet count = 0;
export async function load({ depends }) {
depends('increase:count');
return { count: count++ };
}
src/routes/+page<script>
import { invalidate } from '$app/navigation';
let { data } = $props();
const increase = async () => {
await invalidate('increase:count');
}
</script>
<p>{data.count}<p>
<button on:click={increase}>Increase Count</button>
depends }) => {
// load reruns when `invalidate('https://api.example.com/random-number')` is called...
const const response: Responseresponse = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)fetch('https://api.example.com/random-number');
// ...or when `invalidate('app:random')` is called
depends: (...deps: Array<`${string}:${string}`>) => voidThis function declares that the load function has a dependency on one or more URLs or custom identifiers, which can subsequently be used with invalidate() to cause load to rerun.
Most of the time you won’t need this, as fetch calls depends on your behalf — it’s only necessary if you’re using a custom API client that bypasses fetch.
URLs can be absolute or relative to the page being loaded, and must be encoded.
Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the URI specification.
The following example shows how to use depends to register a dependency on a custom identifier, which is invalidated after a button click, making the load function rerun.
src/routes/+pagelet count = 0;
export async function load({ depends }) {
depends('increase:count');
return { count: count++ };
}
src/routes/+page<script>
import { invalidate } from '$app/navigation';
let { data } = $props();
const increase = async () => {
await invalidate('increase:count');
}
</script>
<p>{data.count}<p>
<button on:click={increase}>Increase Count</button>
depends('app:random');
return {
number: anynumber: await const response: Responseresponse.Body.json(): Promise<any>json()
};
};<script>
import { invalidate, invalidateAll } from '$app/navigation';
/** @type {{ data: import('./$types').PageData }} */
let { data } = $props();
function rerunLoadFunction() {
// any of these will cause the `load` function to rerun
invalidate('app:random');
invalidate('https://api.example.com/random-number');
invalidate(url => url.href.includes('random-number'));
invalidateAll();
}
</script>
<p>random number: {data.number}</p>
<button onclick={rerunLoadFunction}>Update random number</button><script lang="ts">
import { invalidate, invalidateAll } from '$app/navigation';
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
function rerunLoadFunction() {
// any of these will cause the `load` function to rerun
invalidate('app:random');
invalidate('https://api.example.com/random-number');
invalidate(url => url.href.includes('random-number'));
invalidateAll();
}
</script>
<p>random number: {data.number}</p>
<button onclick={rerunLoadFunction}>Update random number</button>load関数はいつ再実行されるのか?
要約すると、load関数は次の状況で再実行されます。
- 値が変更された
paramsのプロパティを参照する場合 - 値が変更された
url(url.pathnameやurl.searchなど)のプロパティを参照する場合。request.urlのプロパティは追跡されません url.searchParams.get(...)、url.searchParams.getAll(...)、またはurl.searchParams.has(...)を呼び出し、問題のパラメーターが変更された場合。url.searchParamsの他のプロパティにアクセスすると、url.searchにアクセスするのと同じ効果があります。await parent()を呼び出し、親のload関数が再実行された場合- 子
load関数がawait parent()を呼び出して再実行されており、親がサーバーのload関数の場合 fetch(ユニバーサルロードのみ)またはdependsを介して特定のURLへの依存関係を宣言し、そのURLがinvalidate(url)で無効とマークされた場合- すべてのアクティブな
load関数がinvalidateAll()で強制的に再実行された場合
paramsとurlは、<a href="..">リンクのクリック、<form>のインタラクション、gotoの呼び出し、またはredirectに応じて変更される可能性があります。
load関数を再実行しても、対応する+layout.svelteまたは+page.svelte内のdataプロパティが更新されるだけであり、コンポーネントが再作成されるわけではないことに注意してください。結果として、内部状態は保持されます。もしこれが望ましくない場合は、afterNavigateコールバック内でリセットする必要があるものをリセットするか、コンポーネントを{#key ...}ブロックで囲むことができます。
認証に関する影響
データのロードに関するいくつかの特徴は、認証チェックに重要な影響を与えます。
- レイアウトの
load関数は、子ルート間のクライアントサイドナビゲーションなど、すべてのリクエストで実行されるわけではありません。(load関数はいつ再実行されるのか?) - レイアウトとページの
load関数は、await parent()が呼び出されない限り、同時に実行されます。レイアウトのload関数がエラーをスローした場合、ページのload関数は実行されますが、クライアントは返されたデータを受け取りません。
保護されたコードの前に認証チェックを確実に行うためのいくつかの可能な戦略があります。
データのウォーターフォールを防ぎ、レイアウトのloadキャッシュを保持するために
load関数が実行される前に、複数のルートを保護するためにhooksを使用してください。- ルート固有の保護のために、
+page.server.jsのload関数で認証ガードを直接使用してください。
+layout.server.jsに認証ガードを配置するには、すべての子ページが保護されたコードの前にawait parent()を呼び出す必要があります。すべての子ページがawait parent()から返されたデータに依存していない限り、他のオプションの方がパフォーマンスが高くなります。