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
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');
};
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
...
/**
* @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;
... 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]
où 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.
charCodeAt(0).Number.toString(radix?: number): string
Returns a string representation of an object.
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]
où 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 desrc/routes/(app)/item/[id]/+layout.svelte
+page@item.svelte
- hérite desrc/routes/(app)/item/+layout.svelte
+page@(app).svelte
- hérite desrc/routes/(app)/+layout.svelte
+page@.svelte
- hérite desrc/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 :
<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>
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) {
// 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: 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) => {
// 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