Charger des données
Avant qu’un composant +page.svelte
(et ses composants
+layout.svelte
parents) puissent être rendus, il est souvent
nécessaire de récupérer des données pour les alimenter. Nous pouvons faire cela en définissant des
fonctions load
.
Données de page
Un fichier +page.svelte
peut avoir un fichier frère +page.js
qui exporte une fonction load
,
dont la valeur de retour est rendue disponible dans la page via la prop data
:
/** @type {import('./$types').PageLoad} */
export function function load({ params }: {
params: any;
}): {
post: {
title: string;
content: string;
};
}
load({ params: any
params }) {
return {
post: {
title: string;
content: string;
}
post: {
title: string
title: `Titre pour ${params: any
params.slug}`,
content: string
content: `Contenu pour ${params: any
params.slug}`
}
};
}
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 = ({ params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) => {
return {
post: {
title: string;
content: string;
}
post: {
title: string
title: `Titre pour ${params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug}`,
content: string
content: `Contenu pour ${params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.slug}`
}
};
};
<script>
/** @type {import('./$types').PageProps} */
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
<script lang="ts">
import type { PageProps } from './$types';
let { data }: PageProps = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
Legacy mode
Avant la version 2.16.0, les props d’une page et d’un layout devaient être typées individuellement :
+page/** @type {{ data: import('./$types').PageData }} */ let {
let data: any
data } =
function $props(): any namespace $props
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
import type {
import PageData
PageData } from './$types'; let {let data: PageData
data }: {data: PageData
data:import PageData
PageData } =
function $props(): any namespace $props
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
En Svelte 4, vous devez plutôt utiliser
export let data
.
Grâce au module $types
que SvelteKit génère, nous profitons pleinement du typage.
Une fonction load
dans un fichier +page.js
est exécutée à la fois sur le serveur et dans le
navigateur (à moins qu’elle soit associée à une déclaration export const ssr = false
, auquel cas
elle ne sera exécutée que dans le navigateur). Si votre fonction load
doit
toujours être exécutée sur le serveur (car elle utilise des variables d’environnement privées, par
exemple, ou parce qu’elle a besoin d’avoir accès à une base de données), alors il faut plutôt la
définir dans un fichier +page.server.js
.
Une version plus réaliste de la fonction load
pour un article de blog, qui ne s’exécute que sur le
serveur et récupère des données dans une base de données, pourrait ressembler à ceci :
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params }) {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"
db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params.slug)
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async ({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params }) => {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"
db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params.slug)
};
};
Notez que le type a changé de PageLoad
à PageServerLoad
, car les fonctions load
de serveur
peuvent accéder à des arguments supplémentaires. Pour comprendre lorsque vous devez utiliser
+page.js
ou +page.server.js
, voir la section Universel vs serveur.
Données de layout
Vos fichiers +layout.svelte
peuvent aussi charger des données, via +layout.js
ou
+layout.server.js
.
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').LayoutServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load() {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"
db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = async () => {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"
db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
};
<script>
/** @type {import('./$types').LayoutProps} */
let { data, children } = $props();
</script>
<main>
<!-- +page.svelte is `@render`ed here -->
{@render children()}
</main>
<aside>
<h2>Plus d'articles</h2>
<ul>
{#each data.posts as post}
<li>
<a href="/blog/{post.slug}">
{post.title}
</a>
</li>
{/each}
</ul>
</aside>
<script lang="ts">
import type { LayoutProps } from './$types';
let { data, children }: LayoutProps = $props();
</script>
<main>
<!-- +page.svelte is `@render`ed here -->
{@render children()}
</main>
<aside>
<h2>Plus d'articles</h2>
<ul>
{#each data.posts as post}
<li>
<a href="/blog/{post.slug}">
{post.title}
</a>
</li>
{/each}
</ul>
</aside>
Legacy mode
LayoutProps
a été ajouté dans la version 2.16.0. Dans les versions antérieures, les propriétés devaient être typées individuellement :+layout/** @type {{ data: import('./$types').LayoutData, children: Snippet }} */ let {
let data: any
data,let children: any
children } =
function $props(): any namespace $props
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
import type {
import LayoutData
LayoutData } from './$types'; let {let data: LayoutData
data,let children: Snippet
children }: {data: LayoutData
data:import LayoutData
LayoutData,children: Snippet
children:type Snippet = /*unresolved*/ any
Snippet } =
function $props(): any namespace $props
$props();Declares the props that a component accepts. Example:
let { optionalProp = 42, requiredProp, bindableProp = $bindable() }: { optionalProp?: number; requiredProps: string; bindableProp: boolean } = $props();
Les données renvoyées par des fonctions load
de layout sont accessibles par les composants
+layout.svelte
et le composant +page.svelte
enfants, ainsi que par le composant de layout auquel
elles sont associées.
<script>
import { page } from '$app/state';
/** @type {import('./$types').PageProps} */
let { data } = $props();
// nous pouvons accéder à `data.posts` car ces données sont renvoyées par
// la fonction `load` du layout parent
let index = $derived(data.posts.findIndex(post => post.slug === page.params.slug));
let next = $derived(data.posts[index + 1]);
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#if next}
<p>Article suivant : <a href="/blog/{next.slug}">{next.title}</a></p>
{/if}
<script lang="ts">
import { page } from '$app/state';
import type { PageProps } from './$types';
let { data }: PageProps = $props();
// nous pouvons accéder à `data.posts` car ces données sont renvoyées par
// la fonction `load` du layout parent
let index = $derived(data.posts.findIndex(post => post.slug === page.params.slug));
let next = $derived(data.posts[index + 1]);
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#if next}
<p>Article suivant : <a href="/blog/{next.slug}">{next.title}</a></p>
{/if}
Si plusieurs fonctions
load
renvoient des données avec la même clé, la dernière “gagne" — le résultat d’une fonctionload
de layout renvoyant{ a: 1, b: 2}
et d’une fonctionload
de page renvoyant{ b: 3, c: 4 }
serait{ a: 1, b: 3, c: 4 }
.
page.data
Le composant +page.svelte
, ainsi que chaque composant +layout.svelte
au-dessus de lui, a accès à
ses propres données en plus de toutes les données venant de ses parents.
Dans certains cas, nous pourrions avoir besoin de l’inverse — un layout parent pourrait avoir besoin
d’avoir accès aux données de page ou aux données d’un layout enfant. Par exemple, le layout racine
pourrait vouloir avoir accès à la propriété title
renvoyée par une fonction load
d’un +page.js
ou +page.server.js
. Ceci est rendu possible par page.data
:
<script>
import { page } from '$app/state';
</script>
<svelte:head>
<title>{page.data.title}</title>
</svelte:head>
<script lang="ts">
import { page } from '$app/state';
</script>
<svelte:head>
<title>{page.data.title}</title>
</svelte:head>
L’information de typage de page.data
est fournie par App.PageData
.
Legacy mode
$app/state
a été ajouté par SvelteKit 2.12. Si vous utilisez une version antérieure ou si vous utilisez Svelte 4, utilisez plutôt$app/stores
. Ce module fournit un store depage
ayant la même interface, et vous pouvez vous y abonner avec, par exemple,$page.data.title
.
Universel vs serveur
Comme nous l’avons vu, il y a deux types de fonctions load
:
- les fichiers
+page.js
et+layout.js
exportent des fonctionsload
universelles qui sont exécutées à la fois sur le serveur et dans le navigateur - les fichiers
+page.server.js
et+layout.server.js
exportent des fonctionsload
de serveur qui ne exécutées que côté serveur
Conceptuellement, elles font la même chose, mais il y a quelques différences importantes dont il faut avoir conscience.
À quel moment chacune est-elle exécutée ?
Les fonctions load
de serveur sont toujours exécutées sur le serveur.
Par défaut, les fonctions load
universelles sont exécutées sur le serveur lors du rendu côté
serveur (SSR) au moment ou un utilisateur ou une utilisatrice visite pour la première fois votre
page. Elles seront de nouveau exécutées lors de l’hydratation, en réutilisant toute réponse venant
de requêtes fetch
. Toutes les invocations suivantes de fonctions load
universelles vont se produire dans le navigateur. Vous pouvez personnaliser ce comportement via les
options de page. Si vous désactivez le rendu côté serveur, votre
application deviendra une SPA et les fonctions load
universelles seront toujours exécutées dans
le navigateur.
Si une route contient à la fois des fonctions load
universelles et de serveur, la fonction load
de serveur est exécutée en premier.
Une fonction load
est invoquée au moment de l’exécution de votre processus, à moins que nous ne
pré-rendiez la page — dans ce cas, elle sera invoquée au moment de la
compilation.
Entrées
Les fonctions load
universelles et de serveur ont toutes deux accès aux propriétés décrivant la
requête (params
, route
, et url
) ainsi qu’à diverses fonctions (fetch
, setHeaders
,
parent
, depends
et untrack
). Ces fonctions sont décrites dans les sections suivantes.
Les fonctions load
de serveur sont appelées avec un ServerLoadEvent
, qui hérite de
clientAddress
, cookies
, locals
, platform
et request
venant de RequestEvent
.
Les fonctions load
universelles sont appelées avec un LoadEvent
, qui a une propriété data
. Si
vous avez une fonction load
à la fois dans +page.js
et dans +page.server.js
(ou +layout.js
et +layout.server.js
), la valeur de retour de la fonction load
de serveur est la propriété
data
dans les arguments de la fonction load
universelle.
Sorties
Une fonction load
universelle peut renvoyer un objet contenant tout type de valeurs, y compris des
choses comme des classes personnalisées et des constructeurs de composants.
Une fonction load
de serveur doit renvoyer des données pouvant être sérialisées avec
devalue — tout ce qui peut être représenté en tant que
JSON plus des choses comme BigInt
, Date
, Map
, Set
et RegExp
, ou des références
répétées/cycliques — afin qu’elles puissent être transportées sur le réseau. Vos données peuvent
inclure des promesses, auquel cas elles seront streamées vers les
navigateurs.
Quand utiliser quoi
Les fonctions load
de serveur sont pratiques lorsque vous avez besoin d’accéder directement à des
données se trouvant dans une base de données ou un système de fichiers, ou si vous avez besoin
d’utiliser des variables d’environnement privées.
Les fonctions load
universelles sont utiles lorsque vous avez besoin de récupérer avec fetch
des
données d’une API externe et que vous n’avez pas besoin d’être authentifié•e pour cela, puisque
SvelteKit peut récupérer directement les données depuis l’API sans avoir à passer par votre serveur.
Elles sont aussi utiles lorsque vous devez renvoyer quelque chose qui ne peut pas être sérialisé,
comme un constructeur de composant Svelte.
Dans de rares cas, vous pourriez avoir besoin des deux ensemble — par exemple, vous pourriez avoir
besoin de renvoyer une instance d’une classe personnalisée qui doit être initialisée avec des
données venant de votre serveur. Lorsque vous utilisez les deux, la valeur de retour de la fonction
load
de serveur n’est pas directement passée à la page, mais à la fonction load
universelle
(en tant que propriété data
) :
/** @type {import('./$types').PageServerLoad} */
export async function function load(): Promise<{
serverMessage: string;
}>
load() {
return {
serverMessage: string
serverMessage: 'bonjour depuis la fonction load de serveur'
};
}
import type { type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async () => {
return {
serverMessage: string
serverMessage: 'bonjour depuis la fonction load de serveur'
};
};
/** @type {import('./$types').PageLoad} */
export async function function load({ data }: {
data: any;
}): Promise<{
serverMessage: any;
universalMessage: string;
}>
load({ data: any
data }) {
return {
serverMessage: any
serverMessage: data: any
data.serverMessage,
universalMessage: string
universalMessage: 'bonjour depuis la fonction load universelle'
};
}
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 = async ({ data: Record<string, any> | null
Contains the data returned by the route’s server load
function (in +layout.server.js
or +page.server.js
), if any.
data }) => {
return {
serverMessage: any
serverMessage: data: Record<string, any> | null
Contains the data returned by the route’s server load
function (in +layout.server.js
or +page.server.js
), if any.
data.serverMessage,
universalMessage: string
universalMessage: 'bonjour depuis la fonction load universelle'
};
};
Utiliser les données d’URL
Souvent, la fonction load
dépend de l’URL d’une manière ou d’une autre. Pour gérer ça, la fonction
load
vous fournit url
route
et params
.
url
Une instance d’URL
, contenant des propriétés
comme origin
, hostname
, pathname
et searchParams
(qui contient les paramètres de recherche
sous la forme d’un objet
URLSearchParams
). url.hash
n’est pas accessible pendant l’exécution de load
, car il n’est pas disponible sur le serveur.
Dans certains environnement,
url
est déduit des en-têtes de requêtes lors du rendu côté serveur. Si vous utilisez l’adaptateur adapter-node, par exemple, vous pourriez avoir besoin de configurer votre adaptateur pour que l’URL soit correcte.
route
Contient le nom du dossier de route actuel, relativement à src/routes
:
/** @type {import('./$types').PageLoad} */
export function function load({ route }: {
route: any;
}): void
load({ route: any
route }) {
var console: Console
The console
module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console
class with methods such as console.log()
, console.error()
and console.warn()
that can be used to write to any Node.js stream.
- A global
console
instance configured to write to process.stdout
and
process.stderr
. The global console
can be used without calling require('console')
.
Warning: The global console object’s methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O
for
more information.
Example using the global console
:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console
class:
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to stdout
with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()
).
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
See util.format()
for more information.
log(route: any
route.id); // '/a/[b]/[...c]'
}
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 = ({ route: {
id: string | null;
}
Info about the current route
route }) => {
var console: Console
The console
module provides a simple debugging console that is similar to the
JavaScript console mechanism provided by web browsers.
The module exports two specific components:
- A
Console
class with methods such as console.log()
, console.error()
and console.warn()
that can be used to write to any Node.js stream.
- A global
console
instance configured to write to process.stdout
and
process.stderr
. The global console
can be used without calling require('console')
.
Warning: The global console object’s methods are neither consistently
synchronous like the browser APIs they resemble, nor are they consistently
asynchronous like all other Node.js streams. See the note on process I/O
for
more information.
Example using the global console
:
console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr
Example using the Console
class:
const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err
console.Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)
Prints to stdout
with newline. Multiple arguments can be passed, with the
first used as the primary message and all additional used as substitution
values similar to printf(3)
(the arguments are all passed to util.format()
).
const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout
See util.format()
for more information.
log(route: {
id: string | null;
}
Info about the current route
route.id: string | null
The ID of the current route - e.g. for src/routes/blog/[slug]
, it would be /blog/[slug]
. It is null
when no route is matched.
id); // '/a/[b]/[...c]'
};
params
params
est construit à partir de url.pathname
et route.id
.
Étant donné une route.id
telle que /a/[b]/[...c]
et un url.pathname
de /a/x/y/z
, l’objet
params
va ressembler à ceci :
{
"b": "x",
"c": "y/z"
}
Faire des requêtes avec fetch
Pour récupérer des données depuis une API externe ou un gestionnaire +server.js
, vous pouvez
utiliser la fonction fetch
fournie, qui se comporte de la même façon que l’API web fetch
native avec quelques fonctionnalités
additionnelles :
- Elle peut être utilisée pour faire de requêtes authentifiées sur le serveur, puisqu’elle hérite
des en-têtes
cookie
etauthorization
de la requête de page. - Elle peut faire des requêtes relatives au serveur (normallement,
fetch
requiert une URL avec une origine lorsqu’utilisée dans un contexte serveur). - Les requêtes internes (par ex. pour les routes
+server.js
) vont appeler directement la fonction de gestion lorsqu’exécutée sur le serveur, sans le surcoût d’un appel HTTP. - Lors du rendu côté serveur, la réponse sera capturée et inlinée dans le HTML rendu en s’appuyant
sur les méthodes
text
,json
etarrayBuffer
de l’objetResponse
. Notez que les en-têtes ne seront pas sérialisées, à moins d’être explicitement incluses viafilterSerializedResponseHeaders
. - Lors de l’hydratation, la réponse sera lue depuis le HTML, garantissant la consistance et
empêchant une requête additionnelle — si vous voyez un avertissement dans votre console de
navigateur lorsque vous utilisez le
fetch
natif du navigateur plutôt que lefetch
deload
, en voici la raison.
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, params }: {
fetch: any;
params: any;
}): Promise<{
item: any;
}>
load({ fetch: any
fetch, params: any
params }) {
const const res: any
res = await fetch: any
fetch(`/api/items/${params: any
params.id}`);
const const item: any
item = await const res: any
res.json();
return { item: any
item };
}
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 = async ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch
is equivalent to the native fetch
web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie
and authorization
headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js
routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text
and json
methods of the Response
object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch, params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params }) => {
const const res: Response
res = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)
fetch(`/api/items/${params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params.id}`);
const const item: any
item = await const res: Response
res.Body.json(): Promise<any>
json();
return { item: any
item };
};
Cookies
Une fonction load
de serveur peut récupérer et définir des cookies
.
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').LayoutServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ cookies: Cookies
Get or set cookies related to the current request
cookies }) {
const const sessionid: string | undefined
sessionid = cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefined
Gets a cookie that was previously set with cookies.set
, or from the request headers.
get('sessionid');
return {
user: {
name: string;
avatar: string;
}
user: await module "$lib/server/database"
db.function getUser(sessionid: string | undefined): Promise<{
name: string;
avatar: string;
}>
getUser(const sessionid: string | undefined
sessionid)
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = async ({ cookies: Cookies
Get or set cookies related to the current request
cookies }) => {
const const sessionid: string | undefined
sessionid = cookies: Cookies
Get or set cookies related to the current request
cookies.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefined
Gets a cookie that was previously set with cookies.set
, or from the request headers.
get('sessionid');
return {
user: {
name: string;
avatar: string;
}
user: await module "$lib/server/database"
db.function getUser(sessionid: string | undefined): Promise<{
name: string;
avatar: string;
}>
getUser(const sessionid: string | undefined
sessionid)
};
};
Les cookies ne seront passées à la fonction fetch
de load
que si l’hôte cible est le même que
celui de l’application SvelteKit, ou un sous-domaine spécifique de ce dernier.
Par exemple, si SvelteKit sert le domaine my.domain.com :
- domain.com NE VA PAS recevoir de cookies
- my.domain.com VA recevoir des cookies
- api.domain.com NE VA PAS recevoir des cookies
- sub.my.domain.com VA recevoir des cookies
Les autres cookies ne seront pas fournis lorsque credentials: 'include'
est défini, car SvelteKit
ne connaît pas les domaines auxquels chaque cookie appartient (le navigateur ne fournit pas cette
information), et il ne serait donc pas sécurisé de les fournir. Utiliser le hook
handleFetch
pour contourner le problème.
En-têtes
Les fonctions load
universelles et de serveur ont toutes les deux accès à une fonction
setHeaders
qui, lorsqu’exécutée sur le serveur, peut définir les en-têtes de la réponse.
(Lorsqu’exécutée dans le navigateur, setHeaders
n’a pas d’effet.) C’est utile si vous souhaitez
que la page puisse être mise en cache, par exemple :
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, setHeaders }: {
fetch: any;
setHeaders: any;
}): Promise<any>
load({ fetch: any
fetch, setHeaders: any
setHeaders }) {
const const url: "https://cms.example.com/products.json"
url = `https://cms.example.com/products.json`;
const const response: any
response = await fetch: any
fetch(const url: "https://cms.example.com/products.json"
url);
// Les en-têtes ne sont définies que lors du SSR, pour mettre en cache le HTML de la page pour la
// même durée que la donnée sous-jacente.
setHeaders: any
setHeaders({
age: any
age: const response: any
response.headers.get('age'),
'cache-control': const response: any
response.headers.get('cache-control')
});
return const response: any
response.json();
}
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 = async ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch
is equivalent to the native fetch
web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie
and authorization
headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js
routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text
and json
methods of the Response
object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch, setHeaders: (headers: Record<string, string>) => void
If you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
src/routes/blog/+pageexport async function load({ fetch, setHeaders }) {
const url = `https://cms.example.com/articles.json`;
const response = await fetch(url);
setHeaders({
age: response.headers.get('age'),
'cache-control': response.headers.get('cache-control')
});
return response.json();
}
Setting the same header multiple times (even in separate load
functions) is an error — you can only set a given header once.
You cannot add a set-cookie
header with setHeaders
— use the cookies
API in a server-only load
function instead.
setHeaders
has no effect when a load
function runs in the browser.
setHeaders }) => {
const const url: "https://cms.example.com/products.json"
url = `https://cms.example.com/products.json`;
const const response: Response
response = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)
fetch(const url: "https://cms.example.com/products.json"
url);
// Les en-têtes ne sont définies que lors du SSR, pour mettre en cache le HTML de la page pour la
// même durée que la donnée sous-jacente.
setHeaders: (headers: Record<string, string>) => void
If you need to set headers for the response, you can do so using the this method. This is useful if you want the page to be cached, for example:
src/routes/blog/+pageexport async function load({ fetch, setHeaders }) {
const url = `https://cms.example.com/articles.json`;
const response = await fetch(url);
setHeaders({
age: response.headers.get('age'),
'cache-control': response.headers.get('cache-control')
});
return response.json();
}
Setting the same header multiple times (even in separate load
functions) is an error — you can only set a given header once.
You cannot add a set-cookie
header with setHeaders
— use the cookies
API in a server-only load
function instead.
setHeaders
has no effect when a load
function runs in the browser.
setHeaders({
age: string | null
age: const response: Response
response.Response.headers: Headers
headers.Headers.get(name: string): string | null
get('age'),
'cache-control': const response: Response
response.Response.headers: Headers
headers.Headers.get(name: string): string | null
get('cache-control')
});
return const response: Response
response.Body.json(): Promise<any>
json();
};
Définir la même en-tête plusieurs fois (même dans des fonctions load
séparées) est une erreur.
Vous pouvez seulement définir une en-tête particulière une seule fois en utilisant la fonction
setHeaders
. Vous ne pouvez pas définir l’en-tête set-cookie
avec setHeaders
— utilisez plutôt
cookies.set(name, value, options)
.
Utiliser les données du parent
Parfois, il est utile pour une fonction load
d’avoir accès aux données d’une fonction load
parente, ce qui est possible via await parent()
:
/** @type {import('./$types').LayoutLoad} */
export function function load(): {
a: number;
}
load() {
return { a: number
a: 1 };
}
import type { type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad } from './$types';
export const const load: LayoutLoad
load: type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad = () => {
return { a: number
a: 1 };
};
/** @type {import('./$types').LayoutLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
b: any;
}>
load({ parent: any
parent }) {
const { const a: any
a } = await parent: any
parent();
return { b: any
b: const a: any
a + 1 };
}
import type { type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad } from './$types';
export const const load: LayoutLoad
load: type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type LayoutLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutLoad = async ({ parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) => {
const { const a: any
a } = await parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return { b: any
b: const a: any
a + 1 };
};
/** @type {import('./$types').PageLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
c: any;
}>
load({ parent: any
parent }) {
const { const a: any
a, const b: any
b } = await parent: any
parent();
return { c: any
c: const a: any
a + const b: any
b };
}
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 = async ({ parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) => {
const { const a: any
a, const b: any
b } = await parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return { c: any
c: const a: any
a + const b: any
b };
};
<script>
/** @type {import('./$types').PageProps} */
let { data } = $props();
</script>
<!-- renders `1 + 2 = 3` -->
<p>{data.a} + {data.b} = {data.c}</p>
<script lang="ts">
import type { PageProps } from './$types';
let { data }: PageProps = $props();
</script>
<!-- renders `1 + 2 = 3` -->
<p>{data.a} + {data.b} = {data.c}</p>
Notez que la fonction
load
de+page.js
reçoit la donnée fusionnée des deux fonctionsload
de layout, pas uniquement celles du parent immédiat.
Dans +page.server.js
et +layout.server.js
, parent
renvoie les données des fichiers
+layout.server.js
.
Dans +page.js
ou +layout.js
, parent
renvoie les données des fichiers +layout.js
. Toutefois,
un +layout.js
manquant est considéré comme une fonction ({ data }) => data
, ce qui implique
qu’il va également fournir les données des fichiers +layout.server.js
parents qui ne sont pas
"cachés” par un fichier +layout.js
.
Faites attention à ne pas introduire de “cascades de chargement” lorsque vous utilisez await parent()
. Ici par exemple, getData()
ne dépend pas du résultat de l’appel de parent()
, nous
devrions donc plutôt l’exécuter en premier pour éviter de retarder le rendu.
/** @type {import('./$types').PageLoad} */
export async function function load(event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params, parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) {
const parentData = await parent();
const const data: {
meta: any;
}
data = await function getData(params: Record<string, string>): Promise<{
meta: any;
}>
getData(params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params);
const const parentData: Record<string, any>
parentData = await parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return {
...const data: {
meta: any;
}
data,
meta: any
meta: { ...const parentData: Record<string, any>
parentData.meta, ...const data: {
meta: any;
}
data.meta: any
meta }
};
}
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 = async ({ params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params, parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent }) => {
const parentData = await parent();
const const data: {
meta: any;
}
data = await function getData(params: Record<string, string>): Promise<{
meta: any;
}>
getData(params: Record<string, any>
The parameters of the current page - e.g. for a route like /blog/[slug]
, a { slug: string }
object
params);
const const parentData: Record<string, any>
parentData = await parent: () => Promise<Record<string, any>>
await parent()
returns data from parent +layout.js
load
functions.
Implicitly, a missing +layout.js
is treated as a ({ data }) => data
function, meaning that it will return and forward data from parent +layout.server.js
files.
Be careful not to introduce accidental waterfalls when using await parent()
. If for example you only want to merge parent data into the returned output, call it after fetching your other data.
parent();
return {
...const data: {
meta: any;
}
data,
meta: any
meta: { ...const parentData: Record<string, any>
parentData.meta, ...const data: {
meta: any;
}
data.meta: any
meta }
};
};
Erreurs
Si une erreur est jetée lors d’une fonction load
, la page +error.svelte
la plus
proche sera rendue. Pour les erreurs prévues, utilisez l’utilitaire
error
importé depuis @sveltejs/kit
pour préciser le statut HTTP et un message optionnel :
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').LayoutServerLoad} */
export function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) {
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
} | undefined
user) {
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(401, 'non identifié');
}
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: boolean
isAdmin) {
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(403, 'pas un administrateur');
}
}
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 LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = ({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) => {
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
} | undefined
user) {
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(401, 'non identifié');
}
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: boolean
isAdmin) {
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(403, 'pas un administrateur');
}
};
Appeler error(...)
va lever une exception, ce qui vous permet de facilement arrêter l’exécution
depuis des fonctions utilitaires.
Si une erreur imprévue est levée, SvelteKit va exécuter le hook
handleError
et la traiter comme une erreur 500 Internal Error.
Dans SvelteKit 1.x, vous deviez
throw
l’erreur vous-même.
Redirections
Pour rediriger les utilisateurs et utilisatrices, utilisez l’utilitaire redirect
importé depuis
@sveltejs/kit
et associé à un status 3xx
pour préciser l’endroit vers lequel ils ou elles
devraient être redirigé•e•s. Comme avec error(...)
, exécuter redirect(...)
va jeter une
exception, permettant d’arrêter l’exécution depuis des fonctions utilitaires.
import { function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
/** @type {import('./$types').LayoutServerLoad} */
export function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) {
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
} | undefined
user) {
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect(307, '/login');
}
}
import { function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = ({ locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals }) => {
if (!locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: {
name: string;
} | undefined
user) {
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect(307, '/login');
}
};
N’utilisez pas
redirect()
au sein d’un blocktry {...}
, puisque la redirection va immédiatement déclencher l’exécution ducatch
.
Dans le navigateur, vous pouvez naviguer programmatiquement en dehors d’une fonction load
en
utilisant goto
importé depuis $app/navigation
.
Dans SvelteKit 1.x vous deviez
throw
leredirect
vous-même.
Streamer grâce aux promesses
Lorsque vous utilisez une fonction load
de serveur, les promesses vont être streamées vers le
navigateur à mesure qu’elles se résolvent. Cela peut être utile si vous avez des données lourdes et
non essentielles, puisque vous pouvez commencer le rendu de la page avant que toutes les données
soient disponibles :
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params }) {
return {
// assurez-vous que le `await` se produise à la fin, sinon
// nous ne pouvons pas commencer le chargement des commentaires
// tant que l'article n'est pas chargé
comments: Promise<{
content: string;
}>
comments: const loadComments: (slug: string) => Promise<{
content: string;
}>
loadComments(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params.slug),
post: {
title: string;
content: string;
}
post: await const loadPost: (slug: string) => Promise<{
title: string;
content: string;
}>
loadPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params.slug)
};
}
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async ({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params }) => {
return {
// assurez-vous que le `await` se produise à la fin, sinon
// nous ne pouvons pas commencer le chargement des commentaires
// tant que l'article n'est pas chargé
comments: Promise<{
content: string;
}>
comments: const loadComments: (slug: string) => Promise<{
content: string;
}>
loadComments(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params.slug),
post: {
title: string;
content: string;
}
post: await const loadPost: (slug: string) => Promise<{
title: string;
content: string;
}>
loadPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params.slug)
};
};
C’est utile notamment pour créer des états de chargement, par exemple :
<script>
/** @type {import('./$types').PageProps} */
let { data } = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#await data.comments}
Chargement des commentaires...
{:then comments}
{#each comments as comment}
<p>{comment.content}</p>
{/each}
{:catch error}
<p>erreur lors du chargement des commentaires : {error.message}</p>
{/await}
<script lang="ts">
import type { PageProps } from './$types';
let { data }: PageProps = $props();
</script>
<h1>{data.post.title}</h1>
<div>{@html data.post.content}</div>
{#await data.comments}
Chargement des commentaires...
{:then comments}
{#each comments as comment}
<p>{comment.content}</p>
{/each}
{:catch error}
<p>erreur lors du chargement des commentaires : {error.message}</p>
{/await}
Lorsque vous streamez des données, faites attention à gérer les rejets de promesses correctement.
Plus précisément, le serveur pourrait planter avec une erreur “unhandled promise rejection” (“rejet
de promesse non géré”) si une promesse différée échoue avant le début du rendu (et donc est
"attrapé”), et que celle-ci n’est pas gérée d’une manière ou d’une autre. Lorsque vous utilisez
directement le fetch
de SvelteKit dans une fonction load
, SvelteKit va gérer cette situation
pour vous. Pour les autres promesses, il suffit d’attacher à la promesse un catch
ne faisant rien
de spécial pour la marquer comme gérée.
/** @type {import('./$types').PageServerLoad} */
export function function load({ fetch }: {
fetch: any;
}): {
ok_manual: Promise<never>;
ok_fetch: any;
dangerous_unhandled: Promise<never>;
}
load({ fetch: any
fetch }) {
const const ok_manual: Promise<never>
ok_manual = var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>
Creates a new rejected promise for the provided reason.
reject();
const ok_manual: Promise<never>
ok_manual.Promise<never>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>
Attaches a callback for only the rejection of the Promise.
catch(() => {});
return {
ok_manual: Promise<never>
ok_manual,
ok_fetch: any
ok_fetch: fetch: any
fetch('/fetch/that/could/fail'),
dangerous_unhandled: Promise<never>
dangerous_unhandled: var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>
Creates a new rejected promise for the provided reason.
reject()
};
}
import type { type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageServerLoad = (event: Kit.ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch
is equivalent to the native fetch
web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie
and authorization
headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js
routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text
and json
methods of the Response
object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here.
fetch }) => {
const const ok_manual: Promise<never>
ok_manual = var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>
Creates a new rejected promise for the provided reason.
reject();
const ok_manual: Promise<never>
ok_manual.Promise<never>.catch<void>(onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined): Promise<void>
Attaches a callback for only the rejection of the Promise.
catch(() => {});
return {
ok_manual: Promise<never>
ok_manual,
ok_fetch: Promise<Response>
ok_fetch: fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)
fetch('/fetch/that/could/fail'),
dangerous_unhandled: Promise<never>
dangerous_unhandled: var Promise: PromiseConstructor
Represents the completion of an asynchronous operation
Promise.PromiseConstructor.reject<never>(reason?: any): Promise<never>
Creates a new rejected promise for the provided reason.
reject()
};
};
Sur de plateformes qui ne supportent pas le streaming, comme AWS Lambda ou Firebase, les réponses seront transformées en buffer. Ceci signifie que la page ne sera rendue qu’une fois que toutes les promesses auront été résolues. Si vous utilisez un proxy (par ex. NGINX), assurez-vous qu’il transforme pas les réponses du serveur qu’il relaye en buffers.
Streamer des données ne va fonctionner que si JavaScript est disponible. Vous devriez éviter de renvoyer des promesses depuis une fonction
load
universelle si la page est rendue côté serveur, puisque ces promesses-là ne sont pas streamées — dans ce cas, la promesse est recréée lorsque la fonction est ré-exécutée dans le navigateur.
Les en-têtes et le statut d’une réponse ne peuvent pas être modifiés une fois que la réponse a commencé à être streamée, vous ne pouvez donc pas utiliser
setHeaders
ou des redirections au sein d’une promesses streamée.
Avec SvelteKit 1.x les promesses créées à la racine étaient automatiquement attendues, et uniquement les promesses imbriquées étaient streamées.
Chargement parallèle
Lorsque du rendu d’une page (ou d’une navigation vers une page), SvelteKit exécute toutes les
fonctions load
de manière concurrente, ce qui permet d’éviter une cascade de requêtes. Lors d’une
navigation côté client, les résultats de multiples appels à des fonctions load
sont regroupés dans
une seule réponse. Une fois que toutes les fonctions load
ont renvoyé leur réponse, la page est
rendue.
Ré-exécuter des fonctions load
SvelteKit enregistre les dépendances de chaque fonction load
pour éviter de la ré-exécuter
inutilement lors des navigations.
Par exemple, étant donné une paire de fonctions load
comme celles-ci...
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').PageServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params }) {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"
db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params.slug)
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad } from './$types';
export const const load: PageServerLoad
load: type PageServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageServerLoad = async ({ params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params }) => {
return {
post: {
title: string;
content: string;
}
post: await module "$lib/server/database"
db.function getPost(slug: string): Promise<{
title: string;
content: string;
}>
getPost(params: Record<string, any>
The parameters of the current route - e.g. for a route like /blog/[slug]
, a { slug: string }
object.
params.slug)
};
};
import * as module "$lib/server/database"
db from '$lib/server/database';
/** @type {import('./$types').LayoutServerLoad} */
export async function function load(event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>): MaybePromise<void | Record<string, any>>
load() {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"
db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
}
import * as module "$lib/server/database"
db from '$lib/server/database';
import type { type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad } from './$types';
export const const load: LayoutServerLoad
load: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
LayoutServerLoad = async () => {
return {
posts: {
title: string;
slug: string;
}[]
posts: await module "$lib/server/database"
db.function getPostSummaries(): Promise<Array<{
title: string;
slug: string;
}>>
getPostSummaries()
};
};
... celle dans +page.server.js
sera rejouée si nous naviguons depuis
/blog/trying-the-raw-meat-diet
vers /blog/i-regret-my-choices
car params.slug
a changé. Celle
dans +layout.server.js
ne sera pas rejouée, car ses données sont toujours considérées comme
valides. En d’autres mots, nous n’appellerons pas db.getPostSummaries()
une deuxième fois.
Une fonction load
qui exécute await parent()
sera également rejouée si une fonction load
parente est rejouée.
Le suivi des dépendances ne s’applique pas après que la fonction load
a renvoyé ses données —
par exemple, lire params.x
dans une promesse imbriquée ne va pas
déclencher la ré-exécution de la fonction lorsque params.x
change. (Ne vous inquiétez pas, vous
aurez un avertissement en mode développement si vous faites cela.) Pour éviter cela, lisez le
paramètre dans le corps principal de votre fonction load
.
Les paramètres de recherche sont suivis indépendamment du reste de l’URL. Par exemple, lire
event.url.searchParams.get("x")
dans une fonction load
va déclencher la ré-exécution de la
fonction load
lors d’une navigation depuis ?x=1
vers ?x=2
, mais pas lors d’une navigation
depuis ?x=1&y=1
vers ?x=1&y=2
.
Arrêter le suivi des dépendances
Dans de rares situations, vous pourriez vouloir exclure quelque chose du mécanisme de suivi des
dépendances. Vous pouvez faire cela grâce à la fonction untrack
fournie par load
:
/** @type {import('./$types').PageLoad} */
export async function function load({ untrack, url }: {
untrack: any;
url: any;
}): Promise<{
message: string;
} | undefined>
load({ untrack: any
untrack, url: any
url }) {
// arrête le suivi de url.pathname afin qu'un changement de path de
// déclenche pas une ré-exécution
if (untrack: any
untrack(() => url: any
url.pathname === '/')) {
return { message: string
message: 'Bienvenue !' };
}
}
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 = async ({ untrack: <T>(fn: () => T) => T
Use this function to opt out of dependency tracking for everything that is synchronously called within the callback. Example:
src/routes/+page.serverexport async function load({ untrack, url }) {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack(() => url.pathname === '/')) {
return { message: 'Welcome!' };
}
}
untrack, url: URL
The URL of the current page
url }) => {
// arrête le suivi de url.pathname afin qu'un changement de path de
// déclenche pas une ré-exécution
if (untrack: <boolean>(fn: () => boolean) => boolean
Use this function to opt out of dependency tracking for everything that is synchronously called within the callback. Example:
src/routes/+page.serverexport async function load({ untrack, url }) {
// Untrack url.pathname so that path changes don't trigger a rerun
if (untrack(() => url.pathname === '/')) {
return { message: 'Welcome!' };
}
}
untrack(() => url: URL
The URL of the current page
url.URL.pathname: string
pathname === '/')) {
return { message: string
message: 'Bienvenue !' };
}
};
Invalidation manuelle
Vous pouvez également ré-exécuter des fonctions load
s’appliquant à la page actuelle en utilisant
invalidate(url)
, ce qui ré-exécute toutes les fonctions load
qui
dépendent d’url
, ou invalidateAll()
, qui ré-exécute toutes les
fonctions load
. Les fonctions load
de serveur ne vont jamais être automatiquement dépendantes
d’une url
utilisées par un fetch
pour éviter de fuiter des informations sensibles au client.
Une fonction load
dépend de l’url
si elle exécute fetch(url)
ou depends(url)
. Notez qu’url
peut être un identifiant qui commence par [a-z]
:
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, depends }: {
fetch: any;
depends: any;
}): Promise<{
number: any;
}>
load({ fetch: any
fetch, depends: any
depends }) {
// load est ré-exécutée lorsque `invalidate('https://api.example.com/random-number') est
// appelée...
const const response: any
response = await fetch: any
fetch('https://api.example.com/random-number');
// ... ou lorsque `invalidate('app:random') est appelée
depends: any
depends('app:random');
return {
number: any
number: await const response: any
response.json()
};
}
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 = async ({ fetch: {
(input: RequestInfo | URL, init?: RequestInit): Promise<Response>;
(input: string | URL | globalThis.Request, init?: RequestInit): Promise<Response>;
}
fetch
is equivalent to the native fetch
web API, with a few additional features:
- It can be used to make credentialed requests on the server, as it inherits the
cookie
and authorization
headers for the page request.
- It can make relative requests on the server (ordinarily,
fetch
requires a URL with an origin when used in a server context).
- Internal requests (e.g. for
+server.js
routes) go directly to the handler function when running on the server, without the overhead of an HTTP call.
- During server-side rendering, the response will be captured and inlined into the rendered HTML by hooking into the
text
and json
methods of the Response
object. Note that headers will not be serialized, unless explicitly included via filterSerializedResponseHeaders
- During hydration, the response will be read from the HTML, guaranteeing consistency and preventing an additional network request.
You can learn more about making credentialed requests with cookies here
fetch, depends: (...deps: Array<`${string}:${string}`>) => void
This function declares that the load
function has a dependency on one or more URLs or custom identifiers, which can subsequently be used with invalidate()
to cause load
to rerun.
Most of the time you won’t need this, as fetch
calls depends
on your behalf — it’s only necessary if you’re using a custom API client that bypasses fetch
.
URLs can be absolute or relative to the page being loaded, and must be encoded.
Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the URI specification.
The following example shows how to use depends
to register a dependency on a custom identifier, which is invalidate
d after a button click, making the load
function rerun.
src/routes/+pagelet count = 0;
export async function load({ depends }) {
depends('increase:count');
return { count: count++ };
}
src/routes/+page<script>
import { invalidate } from '$app/navigation';
let { data } = $props();
const increase = async () => {
await invalidate('increase:count');
}
</script>
<p>{data.count}<p>
<button on:click={increase}>Increase Count</button>
depends }) => {
// load est ré-exécutée lorsque `invalidate('https://api.example.com/random-number') est
// appelée...
const const response: Response
response = await fetch: (input: string | URL | globalThis.Request, init?: RequestInit) => Promise<Response> (+1 overload)
fetch('https://api.example.com/random-number');
// ... ou lorsque `invalidate('app:random') est appelée
depends: (...deps: Array<`${string}:${string}`>) => void
This function declares that the load
function has a dependency on one or more URLs or custom identifiers, which can subsequently be used with invalidate()
to cause load
to rerun.
Most of the time you won’t need this, as fetch
calls depends
on your behalf — it’s only necessary if you’re using a custom API client that bypasses fetch
.
URLs can be absolute or relative to the page being loaded, and must be encoded.
Custom identifiers have to be prefixed with one or more lowercase letters followed by a colon to conform to the URI specification.
The following example shows how to use depends
to register a dependency on a custom identifier, which is invalidate
d after a button click, making the load
function rerun.
src/routes/+pagelet count = 0;
export async function load({ depends }) {
depends('increase:count');
return { count: count++ };
}
src/routes/+page<script>
import { invalidate } from '$app/navigation';
let { data } = $props();
const increase = async () => {
await invalidate('increase:count');
}
</script>
<p>{data.count}<p>
<button on:click={increase}>Increase Count</button>
depends('app:random');
return {
number: any
number: await const response: Response
response.Body.json(): Promise<any>
json()
};
};
<script>
import { invalidate, invalidateAll } from '$app/navigation';
/** @type {import('./$types').PageProps} */
let { data } = $props();
function rerunLoadFunction() {
// n'importe laquelle de ces lignes va déclencher la ré-exécution de la fonction `load`
invalidate('app:random');
invalidate('https://api.example.com/random-number');
invalidate(url => url.href.includes('random-number'));
invalidateAll();
}
</script>
<p>nombre aléatoire : {data.number}</p>
<button onclick={rerunLoadFunction}>Changer le nombre aléatoire</button>
<script lang="ts">
import { invalidate, invalidateAll } from '$app/navigation';
import type { PageProps } from './$types';
let { data }: PageProps = $props();
function rerunLoadFunction() {
// n'importe laquelle de ces lignes va déclencher la ré-exécution de la fonction `load`
invalidate('app:random');
invalidate('https://api.example.com/random-number');
invalidate(url => url.href.includes('random-number'));
invalidateAll();
}
</script>
<p>nombre aléatoire : {data.number}</p>
<button onclick={rerunLoadFunction}>Changer le nombre aléatoire</button>
Quand est-ce que les fonctions load sont ré-exécutées ?
En résumé, une fonction load
sera ré-exécutée si elle satisfait l’une des conditions suivantes :
- Elle référence une propriété de
params
dont la valeur a changé - Elle référence une propriété de l’
url
(commeurl.pathname
ouurl.search
) dont la valeur a changé. Les propriétés derequest.url
ne sont pas suivies - Elle exécute
url.searchParams.get(...)
,url.searchParams.getAll(...)
ouurl.searchParams.has(...)
et le paramètre en question a changé. Lire d’autres propriétés deurl.searchParams
aura le même effet que lireurl.search
. - Elle exécute
await parent()
et une fonctionload
parente a été ré-exécutée - Une fonction
load
enfante exécuteawait parent()
et est ré-exécutée, et le parent est une fonctionload
de serveur - Elle déclare une dépendance sur une URL spécifique via
fetch
(load
universelles uniquement) oudepends
, et cette URL a été déclarée comme obsolète avecinvalidate(url)
- Toutes les fonctions
load
actives ont été ré-exécutées de manière forcée avecinvalidateAll()
params
et url
peuvent changer en réaction à un clic sur un lien <a href="..">
, une
interaction de formulaire, une invocation de
goto
, ou une redirection redirect
.
Notez que ré-exécuter une fonction load
va mettre à jour la propriété data
dans les composants
+layout.svelte
ou +page.svelte
correspondant ; cela ne déclenche pas la re-création du
composant. En conséquence, l’état interne du composant est préservé. Si ce n’est pas ce que vous
souhaitez, vous pouvez réinitialiser ce dont vous avez besoin dans un callback
afterNavigate
, et/ou entourer votre composant d’un bloc {#key ...}
.
Implications pour l’authentification
Quelques fonctionnalités du chargement de données ont des implications importantes pour les vérifications d’authentification :
- Les fonctions
load
de layout ne sont pas ré-exécutées à chaque requête, comme par exemple lors des navigations côté client entre des routes enfantes. (Quand est-ce que les fonctions load sont ré-exécutées ?) - Les fonctions
load
de layout et de page sont exécutées de manière concurrente à moins queawait parent()
soit utilisé. Si une fonctionload
de layout lève une exception, la fonctionload
de page est exécutée, mais le client ne va pas recevoir les données renvoyées.
Il y a quelques stratégies possibles pour garantir qu’une vérification d’authentification soit exécutée avant le code qu’elle est censée protéger.
Pour empêcher des cascades de données et conserver les caches des fonctions load
de layout :
- Utilisez des hooks pour protéger plusieurs routes avant que n’importe quelle fonction
load
ne soit exécutée - Utilisez des vérifications d’authentification directement dans les fonctions
load
de+page.server.js
pour une protection spécifique à certaines routes
Faire des vérification d’authenfication dans une fonction load
de +layout.server.js
nécessite
que toutes les pages enfantes exécutent await parent()
avant l’exécution du code que l’on veut
protéger. À moins que chaque page enfante ne dépende des données renvoyées par await parent()
, les
autres options seront plus performantes.
Utiliser getRequestEvent
Lorsque vous exécutez des fonctions load
de serveur, l’objet event
passé à la fonction en tant
qu’argument peut également être récupéré avec getRequestEvent
. Ceci
permet de partager de la logique (comme des vérifications d’authentification) pour accéder à des
informations concernant la requête actuelle sans avoir besoin de la relayer un peu partout.
Par exemple, vous pourriez avoir une fonction qui nécessite que les utilisateurs et utilisatrices
soient identifié•e•s, et les redirige vers /login
si ce n’est pas le cas :
import { function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect } from '@sveltejs/kit';
import { function getRequestEvent(): RequestEvent<Partial<Record<string, string>>, string | null>
Returns the current RequestEvent
. Can be used inside handle
, load
and actions (and functions called by them).
In environments without AsyncLocalStorage
, this must be called synchronously (i.e. not after an await
).
getRequestEvent } from '$app/server';
export function function requireLogin(): User
requireLogin() {
const { const locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals, const url: URL
The requested URL.
url } = function getRequestEvent(): RequestEvent<Partial<Record<string, string>>, string | null>
Returns the current RequestEvent
. Can be used inside handle
, load
and actions (and functions called by them).
In environments without AsyncLocalStorage
, this must be called synchronously (i.e. not after an await
).
getRequestEvent();
// assume `locals.user` is populated in `handle`
if (!const locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: User | undefined
user) {
const const redirectTo: string
redirectTo = const url: URL
The requested URL.
url.URL.pathname: string
pathname + const url: URL
The requested URL.
url.URL.search: string
search;
const const params: URLSearchParams
params = new var URLSearchParams: new (init?: string[][] | Record<string, string> | string | URLSearchParams) => URLSearchParams
URLSearchParams
class is a global reference for require('url').URLSearchParams
https://nodejs.org/api/url.html#class-urlsearchparams
URLSearchParams({ redirectTo: string
redirectTo });
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): never
Redirect a request. When called during request handling, SvelteKit will return a redirect response.
Make sure you’re not catching the thrown redirect, which would prevent SvelteKit from handling it.
Most common status codes:
303 See Other
: redirect as a GET request (often used after a form POST request)
307 Temporary Redirect
: redirect will keep the request method
308 Permanent Redirect
: redirect will keep the request method, SEO will be transferred to the new page
redirect(307, `/login?${const params: URLSearchParams
params}`);
}
return const locals: App.Locals
Contains custom data that was added to the request within the server handle hook
.
locals.App.Locals.user?: User
user;
}
Désormais, vous pouvez exécuter requireLogin
dans toute fonction load
(ou [action de
formulaire]{form-actions), par exemple) pour garantir que la personnes est identifiée :
import { function requireLogin(): User
requireLogin } from '$lib/server/auth';
export function function load(): {
message: string;
}
load() {
const const user: User
user = function requireLogin(): User
requireLogin();
// `user` est garanti d'être un objet user ici, car sinon `requireLogin`
// provoquerait une redirection et nous ne pourrions pas arriver ici
return {
message: string
message: `bonjour ${const user: User
user.User.name: string
name}!`
};
}
En savoir plus
Modifier cette page sur Github