高度なルーティング
レストパラメータ
ルートセグメントの数が不明な場合は、レスト構文を使用できます。たとえば、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.svelteimport { 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): voidload(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.
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: 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.
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): booleanmatch(param: anyparam) {
return param: anyparam === 'apple' || param: anyparam === 'orange';
}import type { type ParamMatcher = (param: string) => booleanThe 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) => booleanThe 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.svelteSvelteKit はどのルートがリクエストされているかを知る必要があります。そのため、次のルールに従ってソートします...
- より具体的なルートが優先されます (たとえば、パラメーターがないルートは、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): numberReturns the Unicode value of the character at the specified location.
charCodeAt(0).Number.toString(radix?: number): stringReturns a string representation of an object.
toString(16); // '3a', hence '[x+3a]'Unicode エスケープシーケンスを使用することもできます。通常、エンコードされていない文字を直接使用できるため、必要ありませんが、何らかの理由でファイル名に絵文字を含めることができない場合は、エスケープされた文字を使用できます。つまり、これらは同等です。
src/routes/[u+d83e][u+dd2a]/+page.svelte
src/routes/🤪/+page.svelteUnicode エスケープシーケンスの形式は [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: 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);
};