メインコンテンツへスキップ

高度なルーティング

レストパラメータ

ルートセグメントの数が不明な場合は、レスト構文を使用できます。たとえば、GitHub のファイルビューアーを次のように実装できます...

/[org]/[repo]/tree/[branch]/[...file]

...この場合、/sveltejs/kit/tree/main/documentation/docs/04-advanced-routing.md のリクエストにより、ページで次のパラメーターが使用可能になります。

{
	org: 'sveltejs',
	repo: 'kit',
	branch: 'main',
	file: 'documentation/docs/04-advanced-routing.md'
}

src/routes/a/[...rest]/z/+page.svelte は、/a/z (つまり、パラメーターがまったくない場合) と、/a/b/z/a/b/c/z などにも一致します。レストパラメーターの値が有効であることを確認してください。たとえば、マッチャーを使用します。

404 ページ

レストパラメーターを使用すると、カスタム 404 をレンダリングすることもできます。これらのルートが指定されている場合...

src/routes/
├ marx-brothers/
│ ├ chico/
│ ├ harpo/
│ ├ groucho/
│ └ +error.svelte
└ +error.svelte

.../marx-brothers/karl にアクセスした場合、一致するルートがないため、marx-brothers/+error.svelte ファイルはレンダリングされません。ネストされたエラーページをレンダリングする場合は、/marx-brothers/* のリクエストに一致するルートを作成し、そこから 404 を返す必要があります。

src/routes/
├ marx-brothers/
| ├ [...path]/
│ ├ chico/
│ ├ harpo/
│ ├ groucho/
│ └ +error.svelte
└ +error.svelte
src/routes/marx-brothers/[...path]/+page
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').PageLoad} */ export function function load(event: any): void
@type{import('./$types').PageLoad}
load
(event: anyevent) {
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
(404, 'Not Found');
}
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 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
= (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>event) => {
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
(404, 'Not Found');
};

404 ケースを処理しない場合、それらは handleError に表示されます

オプションパラメータ

[lang]/home のようなルートには、必須の lang という名前のパラメーターが含まれています。場合によっては、これらのパラメーターをオプションにすると便利です。この例では、homeen/home の両方が同じページを指すようにします。パラメーターを別の括弧のペアで囲むことで、それを行うことができます: [[lang]]/home

オプションのルートパラメーターは、レストパラメーター ([...rest]/[[optional]]) の後に続けることはできません。パラメーターは「貪欲に」一致し、オプションのパラメーターは常に未使用になるためです。

マッチング

src/routes/fruits/[page] のようなルートは /fruits/apple に一致しますが、/fruits/rocketship にも一致します。それは望ましくありません。パラメーター文字列 ("apple" または "rocketship") を受け取り、それが有効な場合は true を返す _マッチャー_ を params ディレクトリに追加することで、ルートパラメーターが整形式であることを保証できます...

src/params/fruit
/**
 * @param {string} param
 * @return {param is ('apple' | 'orange')}
 * @satisfies {import('@sveltejs/kit').ParamMatcher}
 */
export function function match(param: any): boolean
@paramparam
@return@satisfies{import('@sveltejs/kit').ParamMatcher}
match
(param: any
@paramparam
param
) {
return param: any
@paramparam
param
=== 'apple' || param: any
@paramparam
param
=== 'orange';
}
import type { type ParamMatcher = (param: string) => boolean

The shape of a param matcher. See matching for more info.

ParamMatcher
} from '@sveltejs/kit';
export const const match: (param: string) => param is ("apple" | "orange")match = ((param: stringparam: string): param: stringparam is ('apple' | 'orange') => { return param: stringparam === 'apple' || param: stringparam === 'orange'; }) satisfies type ParamMatcher = (param: string) => boolean

The shape of a param matcher. See matching for more info.

ParamMatcher
;

...そして、ルートを拡張します

src/routes/fruits/[page=fruit]

パス名が一致しない場合、SvelteKit は (以下で指定されたソート順を使用して) 他のルートとの一致を試み、最終的に 404 を返します。

params ディレクトリ内の各モジュールは、マッチャーに対応します。ただし、マッチャーを単体テストするために使用できる *.test.js および *.spec.js ファイルは除きます。

マッチャーは、サーバーとブラウザの両方で実行されます。

ソート

複数のルートが特定のパスに一致する可能性があります。たとえば、これらの各ルートは /foo-abc に一致します

src/routes/[...catchall]/+page.svelte
src/routes/[[a=x]]/+page.svelte
src/routes/[b]/+page.svelte
src/routes/foo-[c]/+page.svelte
src/routes/foo-abc/+page.svelte

SvelteKit はどのルートがリクエストされているかを知る必要があります。そのため、次のルールに従ってソートします...

  • より具体的なルートが優先されます (たとえば、パラメーターがないルートは、1 つの動的パラメーターがあるルートよりも具体的です。)
  • マッチャーを持つパラメーター ([name=type]) は、マッチャーを持たないパラメーター ([name]) よりも優先されます
  • [[optional]] および [...rest] パラメーターは、ルートの最後の部分である場合を除き、無視されます。その場合、最低の優先度で扱われます。つまり、ソートの目的では、x/[[y]]/zx/z と同等に扱われます。
  • 同順位はアルファベット順に解決されます

...これにより、この順序になります。つまり、/foo-abcsrc/routes/foo-abc/+page.svelte を呼び出し、/foo-def は、具体性の低いルートではなく、src/routes/foo-[c]/+page.svelte を呼び出します。

src/routes/foo-abc/+page.svelte
src/routes/foo-[c]/+page.svelte
src/routes/[[a=x]]/+page.svelte
src/routes/[b]/+page.svelte
src/routes/[...catchall]/+page.svelte

エンコーディング

一部の文字は、ファイルシステムで使用できません。Linux および Mac では /、Windows では \ / : * ? " < > | です。# および % 文字は URL で特別な意味を持ち、[ ] ( ) 文字は SvelteKit にとって特別な意味を持つため、これらをルートの一部として直接使用することもできません。

これらの文字をルートで使用するには、16 進数のエスケープシーケンスを使用できます。これは、[x+nn] の形式です。ここで、nn は 16 進数の文字コードです。

  • \[x+5c]
  • /[x+2f]
  • :[x+3a]
  • *[x+2a]
  • ?[x+3f]
  • "[x+22]
  • <[x+3c]
  • >[x+3e]
  • |[x+7c]
  • #[x+23]
  • %[x+25]
  • [[x+5b]
  • ][x+5d]
  • ([x+28]
  • )[x+29]

たとえば、/smileys/:-) ルートを作成するには、src/routes/smileys/[x+3a]-[x+29]/+page.svelte ファイルを作成します。

JavaScript を使用して、文字の 16 進数コードを決定できます

':'.String.charCodeAt(index: number): number

Returns the Unicode value of the character at the specified location.

@paramindex The zero-based index of the desired character. If there is no character at the specified index, NaN is returned.
charCodeAt
(0).Number.toString(radix?: number): string

Returns a string representation of an object.

@paramradix Specifies a radix for converting numeric values to strings. This value is only used for numbers.
toString
(16); // '3a', hence '[x+3a]'

Unicode エスケープシーケンスを使用することもできます。通常、エンコードされていない文字を直接使用できるため、必要ありませんが、何らかの理由でファイル名に絵文字を含めることができない場合は、エスケープされた文字を使用できます。つまり、これらは同等です。

src/routes/[u+d83e][u+dd2a]/+page.svelte
src/routes/🤪/+page.svelte

Unicode エスケープシーケンスの形式は [u+nnnn] です。ここで、nnnn0000 から 10ffff までの有効な値です。(JavaScript の文字列エスケープとは異なり、ffff を超えるコードポイントを表すためにサロゲートペアを使用する必要はありません。) Unicode エンコーディングの詳細については、Unicode を使用したプログラミング を参照してください。

TypeScript は先頭に . 文字が付いたディレクトリで 苦労するため、.well-known ルートを作成する場合などに、これらの文字をエンコードすると便利です: src/routes/[x+2e]well-known/...

高度なレイアウト

デフォルトでは、_レイアウト階層_ は _ルート階層_ を反映します。場合によっては、それが望ましくない可能性があります。

(group)

一部のルートが、1 つのレイアウトを持つべき「アプリ」ルート (たとえば、/dashboard/item) であり、他のルートが別のレイアウトを持つべき「マーケティング」ルート (/about/testimonials) であるとします。これらのルートを、名前が括弧で囲まれたディレクトリでグループ化できます。通常のディレクトリとは異なり、(app) および (marketing) は、その内部のルートの URL パス名には影響しません。

src/routes/
│ (app)/
│ ├ dashboard/
│ ├ item/
│ └ +layout.svelte
│ (marketing)/
│ ├ about/
│ ├ testimonials/
│ └ +layout.svelte
├ admin/
└ +layout.svelte

/(app) ページまたは (marketing) ページである場合など、(group) 内に +page を直接配置することもできます。

レイアウトからの脱出

ルートレイアウトはアプリのすべてのページに適用されます。省略した場合、デフォルトは {@render children()} です。一部のページが他のページと異なるレイアウト階層を持つ必要がある場合は、共通レイアウトを継承する必要がないルートを _除く_ 1 つ以上のグループ内にアプリ全体を配置できます。

上記の例では、/admin ルートは (app) レイアウトまたは (marketing) レイアウトを継承しません。

+page@

ページは、ルートごとに現在のレイアウト階層から抜け出すことができます。前の例の (app) グループ内に /item/[id]/embed ルートがあるとします

src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
│ │ │ │ └ +page.svelte
│ │ │ └ +layout.svelte
│ │ └ +layout.svelte
│ └ +layout.svelte
└ +layout.svelte

通常、これはルートレイアウト、(app) レイアウト、item レイアウト、および [id] レイアウトを継承します。セグメント名、またはルートレイアウトの場合は空の文字列の後に @ を追加することで、それらのレイアウトのいずれかにリセットできます。この例では、次のオプションから選択できます

  • +page@[id].svelte - src/routes/(app)/item/[id]/+layout.svelte から継承します
  • +page@item.svelte - src/routes/(app)/item/+layout.svelte から継承します
  • +page@(app).svelte - src/routes/(app)/+layout.svelte から継承します
  • +page@.svelte - src/routes/+layout.svelte から継承します
src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
│ │ │ │ └ +page@(app).svelte
│ │ │ └ +layout.svelte
│ │ └ +layout.svelte
│ └ +layout.svelte
└ +layout.svelte

+layout@

ページと同様に、レイアウトは同じ手法を使用して、親レイアウト階層から _それ自体_ を脱出できます。たとえば、+layout@.svelte コンポーネントは、すべての子ルートの階層をリセットします。

src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
│ │ │ │ └ +page.svelte  // uses (app)/item/[id]/+layout.svelte
│ │ │ ├ +layout.svelte  // inherits from (app)/item/+layout@.svelte
│ │ │ └ +page.svelte    // uses (app)/item/+layout@.svelte
│ │ └ +layout@.svelte   // inherits from root layout, skipping (app)/+layout.svelte
│ └ +layout.svelte
└ +layout.svelte

レイアウトグループを使用するタイミング

すべてのユースケースがレイアウトのグループ化に適しているわけではありませんし、無理に使う必要もありません。ユースケースによっては、複雑な(group)のネストが発生したり、単一の例外のために(group)を導入したくない場合もあるでしょう。再利用可能なload関数やSvelteコンポーネントなどのコンポジション(構成)や、if文を使って目的を達成することも全く問題ありません。次の例は、ルートレイアウトに巻き戻り、他のレイアウトも使用できるコンポーネントや関数を再利用するレイアウトを示しています。

src/routes/nested/route/+layout@
<script>
	import ReusableLayout from '$lib/ReusableLayout.svelte';
	let { data, children } = $props();
</script>

<ReusableLayout {data}>
	{@render children()}
</ReusableLayout>
src/routes/nested/route/+layout
import { function reusableLoad(event: import("@sveltejs/kit").LoadEvent): Promise<Record<string, any>>reusableLoad } from '$lib/reusable-load-function';

/** @type {import('./$types').PageLoad} */
export 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
(event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>event) {
// Add additional logic here, if needed return function reusableLoad(event: import("@sveltejs/kit").LoadEvent): Promise<Record<string, any>>reusableLoad(event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>event); }
import { function reusableLoad(event: import("@sveltejs/kit").LoadEvent): Promise<Record<string, any>>reusableLoad } from '$lib/reusable-load-function';
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 = (event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>event) => {
	// Add additional logic here, if needed
	return function reusableLoad(event: import("@sveltejs/kit").LoadEvent): Promise<Record<string, any>>reusableLoad(event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>event);
};

さらに詳しく

GitHubでこのページを編集