高度なルーティング
レストパラメータ
ルートセグメントの数が不明な場合は、レスト構文を使用できます。たとえば、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
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').PageLoad} */
export function function load(event: any): void
load(event: any
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.
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.
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: 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 = (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.
error(404, 'Not Found');
};
404 ケースを処理しない場合、それらは
handleError
に表示されます
オプションパラメータ
[lang]/home
のようなルートには、必須の lang
という名前のパラメーターが含まれています。場合によっては、これらのパラメーターをオプションにすると便利です。この例では、home
と en/home
の両方が同じページを指すようにします。パラメーターを別の括弧のペアで囲むことで、それを行うことができます: [[lang]]/home
オプションのルートパラメーターは、レストパラメーター ([...rest]/[[optional]]
) の後に続けることはできません。パラメーターは「貪欲に」一致し、オプションのパラメーターは常に未使用になるためです。
マッチング
src/routes/fruits/[page]
のようなルートは /fruits/apple
に一致しますが、/fruits/rocketship
にも一致します。それは望ましくありません。パラメーター文字列 ("apple"
または "rocketship"
) を受け取り、それが有効な場合は true
を返す _マッチャー_ を params
ディレクトリに追加することで、ルートパラメーターが整形式であることを保証できます...
/**
* @param {string} param
* @return {param is ('apple' | 'orange')}
* @satisfies {import('@sveltejs/kit').ParamMatcher}
*/
export function function match(param: any): boolean
match(param: any
param) {
return param: any
param === 'apple' || param: any
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: string
param: string): param: string
param is ('apple' | 'orange') => {
return param: string
param === 'apple' || param: string
param === '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]]/z
はx/z
と同等に扱われます。- 同順位はアルファベット順に解決されます
...これにより、この順序になります。つまり、/foo-abc
は src/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.
charCodeAt(0).Number.toString(radix?: number): string
Returns a string representation of an object.
toString(16); // '3a', hence '[x+3a]'
Unicode エスケープシーケンスを使用することもできます。通常、エンコードされていない文字を直接使用できるため、必要ありませんが、何らかの理由でファイル名に絵文字を含めることができない場合は、エスケープされた文字を使用できます。つまり、これらは同等です。
src/routes/[u+d83e][u+dd2a]/+page.svelte
src/routes/🤪/+page.svelte
Unicode エスケープシーケンスの形式は [u+nnnn]
です。ここで、nnnn
は 0000
から 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文を使って目的を達成することも全く問題ありません。次の例は、ルートレイアウトに巻き戻り、他のレイアウトも使用できるコンポーネントや関数を再利用するレイアウトを示しています。
<script>
import ReusableLayout from '$lib/ReusableLayout.svelte';
let { data, children } = $props();
</script>
<ReusableLayout {data}>
{@render children()}
</ReusableLayout>
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>>
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: PageLoad
load: 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);
};