データの読み込み
+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: any
params }) {
return {
post: {
title: string;
content: string;
}
post: {
title: string
title: `Title for ${params: any
params.slug} goes here`,
content: string
content: `Content for ${params: any
params.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: PageLoad
load: 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: string
title: `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: string
content: `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: PageServerLoad
load: 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: LayoutServerLoad
load: 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: string
serverMessage: '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: PageServerLoad
load: 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: string
serverMessage: 'hello from server load function'
};
};
/** @type {import('./$types').PageLoad} */
export async function function load({ data }: {
data: any;
}): Promise<{
serverMessage: any;
universalMessage: string;
}>
load({ data: any
data }) {
return {
serverMessage: any
serverMessage: data: any
data.serverMessage,
universalMessage: string
universalMessage: '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: PageLoad
load: 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> | null
Contains the data returned by the route’s server load
function (in +layout.server.js
or +page.server.js
), if any.
data }) => {
return {
serverMessage: any
serverMessage: data: Record<string, any> | null
Contains the data returned by the route’s server load
function (in +layout.server.js
or +page.server.js
), if any.
data.serverMessage,
universalMessage: string
universalMessage: '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: any
route }) {
var console: Console
The 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: any
route.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: PageLoad
load: 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: Console
The 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 | null
The 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: any
fetch, params: any
params }) {
const const res: any
res = await fetch: any
fetch(`/api/items/${params: any
params.id}`);
const const item: any
item = await const res: any
res.json();
return { item: any
item };
}
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: PageLoad
load: 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: Response
res = 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: any
item = await const res: Response
res.Body.json(): Promise<any>
json();
return { item: any
item };
};
クッキー
サーバーの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: Cookies
Get or set cookies related to the current request
cookies }) {
const const sessionid: string | undefined
sessionid = cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get(name: string, opts?: CookieParseOptions): string | undefined
Gets 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 | undefined
sessionid)
};
}
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: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = async ({ cookies: Cookies
Get or set cookies related to the current request
cookies }) => {
const const sessionid: string | undefined
sessionid = cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get(name: string, opts?: CookieParseOptions): string | undefined
Gets 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 | undefined
sessionid)
};
};
クッキーは、ターゲットホストが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: any
fetch, setHeaders: any
setHeaders }) {
const const url: "https://cms.example.com/products.json"
url = `https://cms.example.com/products.json`;
const const response: any
response = await fetch: any
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: any
setHeaders({
age: any
age: const response: any
response.headers.get('age'),
'cache-control': const response: any
response.headers.get('cache-control')
});
return const response: any
response.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: PageLoad
load: 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>) => void
If 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: Response
response = 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>) => void
If 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 | null
age: const response: Response
response.Response.headers: Headers
headers.Headers.get(name: string): string | null
get('age'),
'cache-control': const response: Response
response.Response.headers: Headers
headers.Headers.get(name: string): string | null
get('cache-control')
});
return const response: Response
response.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: number
a: 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: LayoutLoad
load: 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: number
a: 1 };
};
/** @type {import('./$types').LayoutLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
b: any;
}>
load({ parent: any
parent }) {
const { const a: any
a } = await parent: any
parent();
return { b: any
b: const a: any
a + 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: LayoutLoad
load: 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: any
a } = 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: any
b: const a: any
a + 1 };
};
/** @type {import('./$types').PageLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
c: any;
}>
load({ parent: any
parent }) {
const { const a: any
a, const b: any
b } = await parent: any
parent();
return { c: any
c: const a: any
a + const b: any
b };
}
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: PageLoad
load: 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: any
a, const b: any
b } = 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: any
c: const a: any
a + const b: any
b };
};
<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: any
meta: { ...const parentData: Record<string, any>
parentData.meta, ...const data: {
meta: any;
}
data.meta: any
meta }
};
}
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: PageLoad
load: 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: any
meta: { ...const parentData: Record<string, any>
parentData.meta, ...const data: {
meta: any;
}
data.meta: any
meta }
};
};
エラー
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.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) {
if (!locals: App.Locals
Contains 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.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: boolean
isAdmin) {
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: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = ({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) => {
if (!locals: App.Locals
Contains 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.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: boolean
isAdmin) {
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): never
Redirect 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.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) {
if (!locals: App.Locals
Contains 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): never
Redirect 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): never
Redirect 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: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = ({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) => {
if (!locals: App.Locals
Contains 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): never
Redirect 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: PageServerLoad
load: 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: any
fetch }) {
const const ok_manual: Promise<never>
ok_manual = var Promise: PromiseConstructor
Represents 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: any
ok_fetch: fetch: any
fetch('/fetch/that/could/fail'),
dangerous_unhandled: Promise<never>
dangerous_unhandled: var Promise: PromiseConstructor
Represents 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: PageServerLoad
load: 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: PromiseConstructor
Represents 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: PromiseConstructor
Represents 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: PageServerLoad
load: 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: LayoutServerLoad
load: 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: any
untrack, url: any
url }) {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack: any
untrack(() => url: any
url.pathname === '/')) {
return { message: string
message: '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: PageLoad
load: 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) => T
Use 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: URL
The URL of the current page
url }) => {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack: <boolean>(fn: () => boolean) => boolean
Use 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: URL
The URL of the current page
url.URL.pathname: string
pathname === '/')) {
return { message: string
message: '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: any
fetch, depends: any
depends }) {
// load reruns when `invalidate('https://api.example.com/random-number')` is called...
const const response: any
response = await fetch: any
fetch('https://api.example.com/random-number');
// ...or when `invalidate('app:random')` is called
depends: any
depends('app:random');
return {
number: any
number: await const response: any
response.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: PageLoad
load: 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}`>) => void
This 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 invalidate
d 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: Response
response = 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}`>) => void
This 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 invalidate
d 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: any
number: await const response: Response
response.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()
から返されたデータに依存していない限り、他のオプションの方がパフォーマンスが高くなります。