Skip to main content

Routing avancé

Paramètres de reste

Si le nombre de segments de route est inconnu, vous pouvez utiliser la syntaxe de reste — par exemple vous pourriez implémenter le visualisateur de fichiers de Github de cette manière...

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

... et dans ce cas une requête visant /sveltejs/kit/tree/main/documentation/docs/04-advanced-routing.md va en conséquence rendre disponibles à la page les paramètres suivants :

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

src/routes/a/[...rest]/z/+page.svelte va correspondre à /a/z (c-à-d qu’il n’y a aucun paramètre) ainsi qu’à /a/b/z et /a/b/c/z, et ainsi de suite. Assurez-vous que la valeur du paramètre de reste est valide, en utilisant par exemple un matcher.

Pages 404

Les paramètres de reste vous permettent également d’afficher des pages 404 personnalisées. Étant donné ces routes...

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

... le fichier marx-brothers/+error.svelte ne sera pas affiché si vous vous rendez sur la page /marx-brothers/karl, car aucune route ne correspond. Si vous souhaitez afficher la page d’erreur imbriquée, vous devez créer une route qui correspond à n’importe quelle requête /marx-brothers/*, et renvoyer une erreur 404 depuis cette route :

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');
};

Si vous ne gérez pas les cas 404, ils vont apparaître dans handleError

Paramètres optionnels

Une route comme [lang]/home contient un paramètre nommé lang qui est obligatoire. Il peut être intéressant parfois de rendre ces paramètres optionnels, afin que, dans cet exemple, à la fois home et en/home pointent vers la même page. Vous pouvez faire cela en enrobant le paramètre dans une autre paire de crochets : [[lang]]/home

Notez qu’un paramètre optionnel de route ne peut être directement suivre un paramètre de reste ([...rest]/[[optional]]), puisque la correspondance des paramètres est faite de manière “cupide”, ce qui implique que le paramètre optionnel sera toujours inutilisé.

Matching

Une route comme src/routes/fruits/[page] va matcher /fruits/apple, mais aussi /fruits/rocketship. Ce n’est pas souhaitable. Vous pouvez vous assurer que les paramètres de route sont bien formés en ajoutant un matcher — une fonction qui va prendre en paramètre une chaîne de caractères représentant le paramètre ("apple" ou "rocketship") et renvoie true si le paramètre est valide — à votre dossier 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
;

... et en modifiant les noms de vos dossier de route :

src/routes/fruits/[page=fruit]

Si le chemain ne correspond pas, SvelteKit va essayer de le faire correspondre à d’autres routes (en utilisant l’ordre de tri précisé ci-dessous), avant d’éventuellement renvoyer une 404.

Chaque module dans le dossier params correspond à un matcher, à l’exception des fichiers *.test.js et *.spec.js qui servent généralement à tester unitairement vos matchers.

Les matchers sont éxecutés à la fois sur le serveur et dans le navigateur.

Priorités des routes

Il est possible pour plusieurs routes de correspondre à un chemin donné. Par exemple, chacune de ces routes sont compatibles avec le chemin /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 a besoin de savoir quelle route la requête doit recevoir. Pour cela, il trie les routes compatibles en utilisant les règles suivantes...

  • Les routes plus spécifiques sont prioritaires (par ex. une route sans aucun paramètre est plus spécifique qu’une route avec un paramètre dynamique, et ainsi de suite)
  • Les routes ayant des paramètres avec matcher ([name=type]) sont prioritaires sur celles sans matcher ([name])
  • Les paramètres [[optional]] et [..rest] sont ignorés à moins qu’il ne soient en toute fin de la route, et dans ce cas ils sont traités avec la priorité la plus faible. En d’autres mots, x/[[y]]/z est traitée de manière similaire à x/z en termes de priorité
  • Les égalités sont résolues alphabétiquement

... ce qui produit cet ordre de priorité, amenant /foo-abc à invoquer src/routes/foo-abc/+page.svelte et /foo-def à invoquer src/routes/foo-[c]/+page.svelte, plutôt que des routes moins spécifiques :

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

Encodage

Certains caractères ne peuvent pas être utilisés sur le système de fichiers — / sur Linux et Mac, \ / : * ? " < > | sur Windows. Les caractères # et % ont une signification spéciale dans les URLs, et les caractères [ ] ( ) ont une signification spéciale pour SvelteKit, ils ne peuvent donc pas être utilisés directement pour construire votre route.

Pour utiliser ces caractères dans vos routes, vous pouvez utiliser les séquences d’échappement hexadécimales, qui ont pour format [x+nn]nn est un code de caractère hexadécimal :

  • \[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]

Par exemple, pour créer une route /smileys/:-), vous créeriez un fichier src/routes/smileys/[x+3a]-[x+29]/+page.svelte.

Vous pouvez déterminer le code hexadécimal correspondant à un caractère avec JavaScript :

':'.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', donc '[x+3a]'

Vous pouvez aussi utiliser des séquences d’échappement Unicode. En général, vous ne devriez pas avoir besoin d’utiliser le caractère non encodé directement, mais si — pour une raison quelconque — vous ne pouvez pas avoir un nom de fichier comportant un emoji, par exemple, vous pouvez alors utiliser les caractères échappés. En d’autres mots, ces deux routes sont équivalentes :

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

Le format d’une séquence d’échappement Unicode est [u+nnnn]nnnn est une valeur valide entre 0000 et 10ffff. (À la différence de l’échappement de caractères JavaScript, il n’est pas nécessaire d’utiliser des paires de substitution pour représenter des valeurs au-delà de ffff.) Pour en apprendre plus sur l’encodage Unicode, consultez la page Programming with Unicode.

Puisque TypeScript a du mal avec les dossiers commençant par un caractère ., vous pourriez trouver utile d’encoder ces caractères lorsque vous créez par ex. des routes .well-known : src/routes/[x+2e]well-known/...

Layout avancés

Par défaut, la hiérarchie de layout reflète la hiérarchie de route. Dans certaines situations, cela peut ne pas être ce que vous souhaitez.

(group)

Vous avez peut–être quelques routes ‘app’ qui devraient partager le même layout (par ex. /dashboard ou /item), et d’autres routes ‘marketing’ qui devraient avoir un autre layout en commun (/about ou /testimonials). Nous pouvons grouper ces routes au sein d’un dossier dont le nom est entouré de parenthèses — à la différences des dossiers normaux — (app) et (marketing) n’affectent pas le chemin d’URL des routes qu’ils contiennent :

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

Vous pouvez également mettre une +page directement au sein d’un (group), par exemple si / devrait être une page (app) ou (marketing).

S’échapper des layouts

Le layout racine s’applique à toutes les pages de votre application — s’il est omis, SvelteKit va utiliser comme layout par défaut un simple {@render children()}. Si vous souhaitez que certaines pages aient une hiérarchie de layout différente du reste, vous pouvez placer toute votre application dans un ou plusieurs groupes à l’exception des routes qui ne devraient pas hériter des layouts communs.

Dans l’exemple ci-dessus, la route /admin n’hérite ni du layout de (app) ni de celui de (marketing).

+page@

Les pages peuvent s’échapper route par route de la hiérarchie de layout courante. Supposez que nous ayons une route /item/[id]/embed au sein du groupe (app) provenant de l’exemple précédent :

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

D’habitude, cette route devrait hériter du layout racine, du layout (app), du layout item et du layout [id]. Nous pouvons réinitialiser l’héritage sur un layout particulier en suffixant le nom du fichier avec le caractère @ suivi du nom du segment choisi — ou, pour cibler le layout racine, la chaîne de caractère vide. Dans cet exemple, nous pouvons choisir une de des options suivantes :

  • +page@[id].svelte - hérite de src/routes/(app)/item/[id]/+layout.svelte
  • +page@item.svelte - hérite de src/routes/(app)/item/+layout.svelte
  • +page@(app).svelte - hérite de src/routes/(app)/+layout.svelte
  • +page@.svelte - hérite de src/routes/+layout.svelte
src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
│ │ │ │ └ +page@(app).svelte
│ │ │ └ +layout.svelte
│ │ └ +layout.svelte
│ └ +layout.svelte
└ +layout.svelte

+layout@

Comme les pages, les layouts peuvent eux-mêmes s’échapper de leur hiérarchie de layout parente, en utilisant la même technique. Par exemple, un composant +layout@.svelte va réinitialiser la hiérarchie pour toutes ses routes enfant :

src/routes/
├ (app)/
│ ├ item/
│ │ ├ [id]/
│ │ │ ├ embed/
│ │ │ │ └ +page.svelte  // utilise (app)/item/[id]/+layout.svelte
│ │ │ ├ +layout.svelte  // hérite de (app)/item/+layout@.svelte
│ │ │ └ +page.svelte    // utilise (app)/item/+layout@.svelte
│ │ └ +layout@.svelte   // hérite du layout racine, en évitant (app)/+layout.svelte
│ └ +layout.svelte
└ +layout.svelte

Quand utiliser les groupes de layout

Toutes les situations ne sont pas adaptées au groupement de layouts, et vous ne sentez pas obligé•e•s de vous en servir. Il se peut que votre situation en devienne un imbriquement complexe de (group), ou que vous ne souhaitiez pas introduire un (group) pour une seule occurrence. Il est parfaitement acceptable d’utiliser d’autres moyens tels que la composition (des fonctions load ou des composants réutilisables) ou des déclaractions #if pour parvenir à ce que vous souhaitez. L’exemple suivant montre un layout qui se réinitialise au layout racine et réutilise des composants et des fonctions que d’autres layouts peuvent aussi utiliser :

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

<ReusableLayout {data}>
	{@render children()}
</ReusableLayout>
<script lang="ts">
	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) {
// Ajouter de la logique supplémentaire ici, si nécessaire 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) => {
	// Ajouter de la logique supplémentaire ici, si nécessaire
	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);
};

Plus de lecture

Modifier cette page sur Github llms.txt

précédent suivant