Skip to main content

Loading data

+page.svelte コンポーネント (と +layout.svelte コンポーネント) をレンダリングする前に、データを取得する必要があるケースが多いでしょう。load 関数を定義することでこれができるようになります。

Page data

+page.svelte ファイルは、load 関数をエクスポートする +page.js という兄弟ファイルを持つことができ、load 関数の戻り値は page で data プロパティを介して使用することができます。

src/routes/blog/[slug]/+page
/** @type {import('./$types').PageLoad} */
export function 
function load({ params }: {
    params: any;
}): {
    post: {
        title: string;
        content: string;
    };
}
@type{import('./$types').PageLoad}
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`
} }; };
src/routes/blog/[slug]/+page
<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>
Legacy mode

Svelte 4 では、代わりに export let data を使います

生成される $types モジュールのおかげで、完全な型安全性を確保できます。

+page.js ファイルの load 関数はサーバーでもブラウザでも実行されます (ただし、export const ssr = false を設定した場合はブラウザでのみ実行されます)。load 関数を常にサーバーで実行させたければ (例えばプライベートな環境変数を使用していたり、データベースにアクセスする場合など)、代わりに +page.server.jsload 関数を置くとよいでしょう。

例えばブログ記事の load 関数をより現実的なものにするとしたら、以下のように、サーバー上でのみ実行され、データベースからデータを取得する、というものになるでしょう。

src/routes/blog/[slug]/+page.server
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>>
@type{import('./$types').PageServerLoad}
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)
}; };

型が PageLoad から PageServerLoad に変わっていることにご注意ください。server load 関数では追加の引数にアクセスすることができます。どのような場合に +page.js を使用し、どのような場合に +page.server.js を使用するのかを理解するには、Universal vs server を参照してください。

Layout data

+layout.svelte ファイルでも、+layout.js+layout.server.js を通じてデータを読み込むことができます。

src/routes/blog/[slug]/+layout.server
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>>
@type{import('./$types').LayoutServerLoad}
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
()
}; };
src/routes/blog/[slug]/+layout
<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 コンポーネントでも利用可能です。

src/routes/blog/[slug]/+page
<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 コンポーネントは、自身のデータとその親の全てのデータにアクセスすることができます。

場合によっては、その逆も必要かもしれません — 親レイアウトからページのデータや子レイアウトのデータにアクセスする必要があるかもしれません。例えば、最上位のレイアウト(root layout)から、+page.js+page.server.jsload 関数から返された title プロパティにアクセスしたい場合があるでしょう。これは $page.data で行うことができます:

src/routes/+layout
<script>
	import { page } from '$app/stores';
</script>

<svelte:head>
	<title>{$page.data.title}</title>
</svelte:head>

$page.data の型情報は App.PageData から提供されます。

Universal vs server

これまで見てきたように、load 関数には2つの種類があります:

  • +page.js ファイルと +layout.js ファイルは、サーバーとブラウザの両方で実行される universal load 関数をエクスポートします
  • +page.server.js ファイルと +layout.server.js ファイルは、サーバーサイドでのみ実行される server load 関数をエクスポートします

概念上は同じものですが、気をつけなければならない重要な違いがあります。

いつ、どの load 関数が実行されるのか?

server load 関数は 常に サーバーで実行されます。

デフォルトでは、universal load 関数は、ユーザーがはじめてページにアクセスしたときの SSR 中にサーバーで実行されます。そのあとのハイドレーション中に、fetch リクエスト で取得したレスポンスを再利用してもう一度実行されます。それ以降の universal load 関数の呼び出しは、すべてブラウザで行われます。この動作は page options によってカスタマイズすることができます。サーバーサイドレンダリング を無効にした場合、SPA となるため、universal load 関数は 常に クライアントで実行されるようになります。

ルート(route)に universal と server の両方の load 関数が含まれている場合、server load が最初に実谷されます。

load 関数は実行時に呼び出されます。ページを プリレンダリング する場合は、ビルド時に呼び出されます。

Input

universal load 関数と server load 関数はどちらも、リクエストを表すプロパティ (paramsrouteurl) と様々な関数 (fetchsetHeadersparentdependsuntrack) にアクセスできます。これらについては、以下のセクションで説明します。

server load 関数は ServerLoadEvent を引数にとって呼び出されます。ServerLoadEvent は、RequestEvent から clientAddresscookieslocalsplatformrequest を継承しています。

universal load 関数は、LoadEvent を引数にとって呼び出されます。LoadEventdata プロパティを持っています。もし +page.js+page.server.js (または +layout.js+layout.server.js) の両方に load 関数がある場合、server load 関数の戻り値が、universal load 関数の引数の data プロパティとなります。

Output

universal load 関数は、任意の値(カスタムクラスやコンポーネントコンストラクタなどを含む)を含むオブジェクトを返すことができます。

server load 関数は、ネットワークで転送できるようにするために、devalue でシリアライズできるデータ (つまり JSON で表現できるものに加え、BigIntDateMapSetRegExp や、繰り返し/循環参照など) を返さなければなりません。データには promises を含めることができ、その場合はブラウザにストリーミングされます。

どちらを使用すべきか

server load 関数は、データベースやファイルシステムからデータを直接アクセスする必要がある場合や、プライベートな環境変数を使用する必要がある場合に有用です。

universal load 関数は、外部の API から データを fetch (取得) する必要があり、プライベートなクレデンシャルが必要ない場合に便利です。なぜなら、SvelteKit はあなたのサーバーを経由せずに、その API から直接データを取得することができるからです。また、Svelte コンポーネントコンストラクタのような、シリアライズできないものを返す必要がある場合にも便利です。

まれに、両方を同時に使用する必要がある場合もあります。例えば、サーバーからのデータで初期化されたカスタムクラスのインスタンスを返す必要がある場合です。両方を使用する場合は、server load の戻り値は直接ページには渡されず、universal load 関数に (data プロパティとして) 渡されます:

src/routes/+page.server
/** @type {import('./$types').PageServerLoad} */
export async function 
function load(): Promise<{
    serverMessage: string;
}>
@type{import('./$types').PageServerLoad}
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' }; };
src/routes/+page
/** @type {import('./$types').PageLoad} */
export async function 
function load({ data }: {
    data: any;
}): Promise<{
    serverMessage: any;
    universalMessage: string;
}>
@type{import('./$types').PageLoad}
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> | 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: anyserverMessage: 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: stringuniversalMessage: 'hello from universal load function' }; };

URL data を使用する

多くの場合、load 関数は何らかの形で URL に依存します。そのため、load 関数では urlrouteparams を提供しています。

url

URL のインスタンスで、originhostnamepathnamesearchParams (URLSearchParams オブジェクトとしてパースされたクエリ文字列を含む) を含んでいます。url.hash はサーバーで利用できないため、load 中にアクセスすることはできません。

環境によっては、サーバーサイドレンダリング時のリクエストヘッダからこれが導出されることもあります。例えば adapter-node では、URL を正しく設定するために adapter の設定をする必要があるかもしれません。

route

現在のルート(route)ディレクトリの名前を含んでいます。src/routes との相対です:

src/routes/a/[b]/[...c]/+page
/** @type {import('./$types').PageLoad} */
export function 
function load({ route }: {
    route: any;
}): void
@type{import('./$types').PageLoad}
load
({ route: anyroute }) {
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
@seesource
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.

@sincev0.1.100
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: 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
@seesource
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.

@sincev0.1.100
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

paramsurl.pathnameroute.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 と同じように動作しますが、いくつか追加の機能があります:

  • ページリクエストの cookieauthorization ヘッダーを継承するので、サーバー上でクレデンシャル付きのリクエストを行うことができます
  • サーバー上で、相対パスのリクエストを行うことができます (通常、fetch はサーバーのコンテキストで使用する場合にはオリジン付きの URL が必要です)
  • サーバーで動作している場合、内部リクエスト (例えば +server.js ルート(routes)に対するリクエスト) は直接ハンドラ関数を呼び出すので、HTTP を呼び出すオーバーヘッドがありません
  • サーバーサイドレンダリング中は、Response オブジェクトの text メソッドと json メソッドと arrayBuffer メソッドにフックすることにより、レスポンスはキャプチャされ、レンダリング済の HTML にインライン化されます。ヘッダーは、filterSerializedResponseHeaders で明示的に指定されない限り、シリアライズされないことにご注意ください。
  • ハイドレーション中は、レスポンスは HTML から読み込まれるため、一貫性が保証され、追加のネットワークリクエストを防ぎます。もし、load 関数の fetch ではなくブラウザの fetch を使用しているときにブラウザコンソールに警告が出た場合は、これが理由です。
src/routes/items/[id]/+page
/** @type {import('./$types').PageLoad} */
export async function 
function load({ fetch, params }: {
    fetch: any;
    params: any;
}): Promise<{
    item: any;
}>
@type{import('./$types').PageLoad}
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 }; };

Cookies

server load 関数では cookies を取得したり設定したりすることができます。

src/routes/+layout.server
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>>
@type{import('./$types').LayoutServerLoad}
load
({ cookies: Cookies

Get or set cookies related to the current request

cookies
}) {
const const sessionid: string | undefinedsessionid = 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.

@paramname the name of the cookie
@paramopts the options, passed directly to cookie.parse. See documentation here
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: Cookies

Get or set cookies related to the current request

cookies
}) => {
const const sessionid: string | undefinedsessionid = 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.

@paramname the name of the cookie
@paramopts the options, passed directly to cookie.parse. See documentation here
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)
}; };

Cookie は、ターゲットホストが Sveltekit アプリケーションと同じか、より明確・詳細(specific)なサブドメインである場合にのみ、SvelteKit から提供される fetch 関数を介して引き渡されます。

例えば、SvelteKit が my.domain.com でサーブしている場合:

  • domain.com は cookie を受け取りません
  • my.domain.com は cookie を受け取ります
  • api.domain.com は cookie を受け取りません
  • sub.my.domain.com は cookie を受け取ります

その他の cookie は、credentials: 'include' がセットされているときには渡されません。なぜなら、Sveltekit はどの cookie がどのドメインに属しているかわからないからです (ブラウザはこの情報を渡さないからです)。そのため、cookie を転送するのは安全ではありません。これを回避するには、handleFetch hook をお使いください。

Headers

server load 関数と universal load 関数はどちらも setHeaders 関数にアクセスでき、サーバー上で実行している場合、 レスポンスにヘッダーを設定できます (ブラウザで実行している場合、setHeaders には何の効果もありません)。これは、ページをキャッシュさせる場合に便利です、例えば:

src/routes/products/+page
/** @type {import('./$types').PageLoad} */
export async function 
function load({ fetch, setHeaders }: {
    fetch: any;
    setHeaders: any;
}): Promise<any>
@type{import('./$types').PageLoad}
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>) => 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/+page
export 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>) => 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/+page
export 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 関数であっても) エラーとなります。指定したヘッダーを設定できるのは一度だけです。set-cookie ヘッダーは、setHeaders では追加できません。代わりに、cookies.set(name, value, options) を使用してください。

Using parent data

load 関数が親の load 関数からのデータにアクセスできたら便利なことがあるでしょう。await parent() でこれを行うことができます:

src/routes/+layout
/** @type {import('./$types').LayoutLoad} */
export function 
function load(): {
    a: number;
}
@type{import('./$types').LayoutLoad}
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 }; };
src/routes/abc/+layout
/** @type {import('./$types').LayoutLoad} */
export async function 
function load({ parent }: {
    parent: any;
}): Promise<{
    b: any;
}>
@type{import('./$types').LayoutLoad}
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 }; };
src/routes/abc/+page
/** @type {import('./$types').PageLoad} */
export async function 
function load({ parent }: {
    parent: any;
}): Promise<{
    c: any;
}>
@type{import('./$types').PageLoad}
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 }; };
src/routes/abc/+page
<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.jsload 関数が、直接の親だけなく、両方のレイアウトの load 関数からマージされたデータを受け取っていることにご注意ください。

+page.server.js+layout.server.js の中では、parent は親の +layout.server.js ファイルからデータを取得します。

+page.js+layout.js では、親の +layout.js ファイルからデータを返します。しかし、+layout.js が見つからない場合は ({ data }) => data 関数として扱われます。つまり、+layout.js ファイルによって’シャドウ(shadowed)’されていない親の +layout.server.js ファイルからデータを返します。

await parent() を使用する際はウォータフォールを発生させないよう注意してください。例えば、こちらの getData(params)parent() の呼び出しの結果には依存しないので、レンダリングの遅延を避けるために最初に呼び出すほうが良いでしょう。

+page
/** @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>>
@type{import('./$types').PageLoad}
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 }
}; };

Errors

load 中にエラーがスローされた場合、最も近くにある +error.svelte がレンダリングされます。想定されるエラーには、@sveltejs/kit からインポートできる error ヘルパーを使用して HTTP ステータスコードとオプションのメッセージを指定できます:

src/routes/admin/+layout.server
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.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
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>>
@type{import('./$types').LayoutServerLoad}
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.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
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: 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.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
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.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
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.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.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
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: 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.

@paramstatus The HTTP status code. Must be in the range 400-599.
@parambody An object that conforms to the App.Error type. If a string is passed, it will be used as the message property.
@throwsHttpError This error instructs SvelteKit to initiate HTTP error handling.
@throwsError If the provided status is invalid (not between 400 and 599).
error
(403, 'not an admin');
} };

error(...) を呼び出すと例外がスローされるため、ヘルパー関数の内側から簡単に実行を止めることができます。

予期せぬエラーがスローされた場合、SvelteKit は handleError を呼び出し、それを 500 Internal Error として処理します。

SvelteKit 1.x 系では、ご自分で error を throw する必要がありました

Redirects

ユーザーをリダイレクトさせるには、@sveltejs/kit からインポートできる redirect ヘルパーを使用して、ステータスコード 3xx と一緒にリダイレクト先の location を指定します。error(...) と同じように、redirect(...) を呼び出すと例外がスローされるため、ヘルパー関数の内側から簡単に実行を止めることができます。

src/routes/user/+layout.server
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.

@paramstatus The HTTP status code. Must be in the range 300-308.
@paramlocation The location to redirect to.
@throwsRedirect This error instructs SvelteKit to redirect to the specified location.
@throwsError If the provided status is invalid.
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>>
@type{import('./$types').LayoutServerLoad}
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.

@paramstatus The HTTP status code. Must be in the range 300-308.
@paramlocation The location to redirect to.
@throwsRedirect This error instructs SvelteKit to redirect to the specified location.
@throwsError If the provided status is invalid.
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.

@paramstatus The HTTP status code. Must be in the range 300-308.
@paramlocation The location to redirect to.
@throwsRedirect This error instructs SvelteKit to redirect to the specified location.
@throwsError If the provided status is invalid.
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.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.

@paramstatus The HTTP status code. Must be in the range 300-308.
@paramlocation The location to redirect to.
@throwsRedirect This error instructs SvelteKit to redirect to the specified location.
@throwsError If the provided status is invalid.
redirect
(307, '/login');
} };

try {...} ブロックの中で redirect() を使用してはいけません。redirect がすぐにその catch ステートメントをトリガーしてしまうからです。

ブラウザでは、$app.navigation からインポートできる goto を使うことで、load 関数の外側でプログラム的にナビゲーションを行うことができます。

SvelteKit 1.x 系では、ご自分で redirectthrow する必要がありました

Streaming with promises

server load を使用する場合、promise が解決されると同時にブラウザにストリームされます。これにより、遅くて重要でないデータがある場合でも、すべてのデータが利用可能になる前にページのレンダリングを開始することができます:

src/routes/blog/[slug]/+page.server
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
@type{import('./$types').PageServerLoad}
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)
}; };

これはロード状態(loading states)のスケルトンを作成するのに便利です、例えば:

src/routes/blog/[slug]/+page
<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 の reject を正しく処理するようにしてください。具体的には、レンダリングの開始時点 (本来この時点で catch される) より前に遅延ロード (lazy-loaded) された promise が失敗し、エラーを処理していない場合、server が “unhandled promise rejection” エラーでクラッシュする可能性があります。SvelteKit の fetchload 関数で直接使用する場合は SvelteKit がこのケースを処理してくれます。それ以外の promise の場合は、何もしない catch (noop-catch) をアタッチし、処理済であることを明示するだけで十分です。

src/routes/+page.server
/** @type {import('./$types').PageServerLoad} */
export function 
function load({ fetch }: {
    fetch: any;
}): {
    ok_manual: Promise<never>;
    ok_fetch: any;
    dangerous_unhandled: Promise<never>;
}
@type{import('./$types').PageServerLoad}
load
({ fetch: anyfetch }) {
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.

@paramreason The reason the promise was rejected.
@returnsA new rejected Promise.
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.

@paramonrejected The callback to execute when the Promise is rejected.
@returnsA Promise for the completion of the callback.
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: 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.

@paramreason The reason the promise was rejected.
@returnsA new rejected Promise.
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: 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.

@paramreason The reason the promise was rejected.
@returnsA new rejected Promise.
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.

@paramonrejected The callback to execute when the Promise is rejected.
@returnsA Promise for the completion of the callback.
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.

@paramreason The reason the promise was rejected.
@returnsA new rejected Promise.
reject
()
}; };

AWS Lambda や Firebase のような ストリーミングをサポートしないプラットフォームでは、レスポンスはバッファされます。つまり、すべての promise が解決してからでないとページがレンダリングされないということです。もしプロキシ (例えば NGINX) を使用している場合は、プロキシされたサーバーからのレスポンスをバッファしないようにしてください。

ストリーミングデータは JavaScript が有効なときにのみ動作します。ページがサーバーでレンダリングされる場合、universal load 関数からは promise を返すのは避けたほうがよいでしょう、ストリーミングされないからです (代わりに、関数がブラウザで再実行されるときに promise が再作成されます)。

レスポンスのヘッダーとステータスコードは、レスポンスがストリーミングを開始すると変更することはできなくなります。そのため、ストリームされた promise の中で setHeaders を呼んだりリダイレクトをスローしたりすることはできません。

SvelteKit 1.x 系では、トップレベルの promise は自動的に await され、ネストした promise だけがストリーミングされていました。

Parallel loading

ページをレンダリング (またはページにナビゲーション) するとき、SvelteKit はすべての load 関数を同時に実行し、リクエストのウォーターフォールを回避します。クライアントサイドナビゲーションのときは、複数の server load 関数の呼び出し結果が単一のレスポンスにグループ化されます。すべての load 関数が返されると、ページがレンダリングされます。

load 関数の再実行

SvelteKit は それぞれの load 関数の依存関係を追跡し、ナビゲーションの際に不必要に再実行されるのを回避します。

例えば、このような load 関数のペアがあるとして…

src/routes/blog/[slug]/+page.server
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>>
@type{import('./$types').PageServerLoad}
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)
}; };
src/routes/blog/[slug]/+layout.server
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>>
@type{import('./$types').LayoutServerLoad}
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
()
}; };

…もし、/blog/trying-the-raw-meat-diet から /blog/i-regret-my-choices に移動したら、params.slug が変更されているので、+page.server.js のほうは再実行されるでしょう。+layout.server.js のほうは再実行されません、なぜならデータがまだ有効だからです。言い換えると、db.getPostSummaries() を2回呼び出すことはないということです。

await parent() を呼び出している load 関数は、親の load 関数が再実行された場合に再実行されます。

依存関係の追跡は、load 関数から返したあとには適用されません。例えば、ネストした promise の内側で params.x にアクセスしている場合、params.x が変更されても関数の再実行は行われません (ご心配なく、誤ってこれを行っても開発中に警告が表示されます)。代わりに、load 関数の本体部分でパラメータにアクセスしてください。

search parameter は url の他の部分とは独立し追跡されます。例えば、load 関数の中で event.url.searchParams.get("x") にアクセスすると、?x=1 から ?x=2 にナビゲーションするときにその load 関数が再実行されますが、?x=1&y=1 から ?x=1&y=2 にナビゲーションするときには再実行されません。

Untracking dependencies

まれに、依存関係の追跡メカニズムからなにかを除外したいケースがあります。このような場合、untrack 関数を使用します:

src/routes/+page
/** @type {import('./$types').PageLoad} */
export async function 
function load({ untrack, url }: {
    untrack: any;
    url: any;
}): Promise<{
    message: string;
} | undefined>
@type{import('./$types').PageLoad}
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) => T

Use this function to opt out of dependency tracking for everything that is synchronously called within the callback. Example:

src/routes/+page.server
export 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.server
export 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: stringpathname === '/')) {
return { message: stringmessage: 'Welcome!' }; } };

Manual invalidation

現在のページに適用される load 関数は、invalidate(url) を使用することで再実行させることもできます。これは url に依存しているすべての load 関数を再実行させるものです。invalidateAll() は、すべての load 関数を再実行させます。server load 関数の場合は、クライアントに秘情報が漏れるのを防ぐため、取得した url に自動的に依存することはありません。

load 関数が fetch(url)depends(url) を呼び出している場合、その load 関数は url に依存しています。url には [a-z]: から始まるカスタムの識別子を指定することができることにご注意ください:

src/routes/random-number/+page
/** @type {import('./$types').PageLoad} */
export async function 
function load({ fetch, depends }: {
    fetch: any;
    depends: any;
}): Promise<{
    number: any;
}>
@type{import('./$types').PageLoad}
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}`>) => 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 invalidated after a button click, making the load function rerun.

src/routes/+page
let count = 0;
export async function load({ depends }) {
	depends('increase:count');

	return { count: count++ };
}
src/routes/+page
&#x3C;script>
	import { invalidate } from '$app/navigation';

	let { data } = $props();

	const increase = async () => {
		await invalidate('increase:count');
	}
&#x3C;/script>

&#x3C;p>{data.count}&#x3C;p>
&#x3C;button on:click={increase}>Increase Count&#x3C;/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}`>) => 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 invalidated after a button click, making the load function rerun.

src/routes/+page
let count = 0;
export async function load({ depends }) {
	depends('increase:count');

	return { count: count++ };
}
src/routes/+page
&#x3C;script>
	import { invalidate } from '$app/navigation';

	let { data } = $props();

	const increase = async () => {
		await invalidate('increase:count');
	}
&#x3C;/script>

&#x3C;p>{data.count}&#x3C;p>
&#x3C;button on:click={increase}>Increase Count&#x3C;/button>
depends
('app:random');
return { number: anynumber: await const response: Responseresponse.Body.json(): Promise<any>json() }; };
src/routes/random-number/+page
<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 on:click={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 on:click={rerunLoadFunction}>Update random number</button>

load 関数はいつ再実行されるのか

まとめると、load 関数は以下のシチュエーションで再実行されます:

  • params のプロパティを参照していて、その値が変更された場合
  • url のプロパティ (例えば url.pathnameurl.search) を参照していて、その値が変更された場合。request.url のプロパティは追跡されません
  • url.searchParams.get(...)url.searchParams.getAll(...)url.searchParams.has(...) を呼び出しており、その該当するパラメータが変更された場合。url.searchParams の他のプロパティにアクセスした場合は、url.search にアクセスした場合と同じ効果になる。
  • await parent() を呼び出していて、親の load 関数が再実行されたとき
  • fetch (universal load のみ) や depends を介して特定の URL に対する依存を宣言していて、その URL が invalidate(url) で無効(invalid)であるとマークされた場合
  • invalidateAll() によって全ての有効な load 関数が強制的に再実行された場合

paramsurl は、<a href=".."> リンクのクリックや、<form> のやりとりgoto の呼び出し、redirect に応じて変更されます。

load 関数の再実行は、対応する +layout.svelte+page.svelte 内の data プロパティが更新されるだけで、コンポーネントは再作成されることはありません。結果として、内部の状態は保持されます。もし、この挙動がお望みでなければ、afterNavigate コールバック内でリセットしたり、コンポーネントを {#key ...} ブロックでラップしたりしてリセットすることができます。

認証に対する影響

データ読み込みに関するいくつかの機能は、認証チェックに重要な影響があります:

  • レイアウトの load 関数は、例えばその子ルート間のクライアントサイドナビゲーションなど、すべてのリクエストで実行されるわけではありません (load 関数はいつ再実行されるのか)
  • レイアウトとページの load 関数は、await parent() を呼び出していない限り同時に実行されます。もしレイアウトの load がスローした場合、ページの load 関数は実行されますが、クライアントは戻り値のデータを受け取れません。

保護されたコードの前に認証チェックが行われるようにするには、いくつかの戦略が考えられます。

データのウォータフォールを防ぎつつ、レイアウトの load のキャッシュを保持するには:

  • hooks を使用し、load 関数が実行されるよりも前に複数のルートを保護する
  • ルート固有の保護が必要な場合は +page.server.jsload 関数で直接認証ガード (auth guard) を使用する

認証ガード (auth guard) を +layout.server.js に置くと、全ての子ページで保護されたコードの前で await parent() を呼び出す必要があります。全ての子ページが await parent() の戻り値のデータに依存していないのであれば、他のオプションのほうがパフォーマンスが良いでしょう。

その他の参考資料

Edit this page on GitHub