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: anyparams }) {
return {
post: {
title: string;
content: string;
}
post: {
title: stringtitle: `Titre pour ${params: anyparams.slug}`,
content: stringcontent: `Contenu pour ${params: anyparams.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: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = ({ 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: stringtitle: `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: stringcontent: `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: anydata } =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 PageDataPageData } from './$types'; let {let data: PageDatadata }: {data: PageDatadata:import PageDataPageData } =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: PageServerLoadload: 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: LayoutServerLoadload: 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
LayoutPropsa é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: anydata,let children: anychildren } =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 LayoutDataLayoutData } from './$types'; let {let data: LayoutDatadata,let children: Snippetchildren }: {data: LayoutDatadata:import LayoutDataLayoutData,children: Snippetchildren:type Snippet = /*unresolved*/ anySnippet } =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
loadrenvoient des données avec la même clé, la dernière “gagne" — le résultat d’une fonctionloadde layout renvoyant{ a: 1, b: 2}et d’une fonctionloadde 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/statea é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 depageayant 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.jset+layout.jsexportent des fonctionsloaduniverselles qui sont exécutées à la fois sur le serveur et dans le navigateur - les fichiers
+page.server.jset+layout.server.jsexportent des fonctionsloadde 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. Si vous avez besoin de sérialiser/désérialiser des types personnalisés, veuillez
utiliser les hooks de transport.
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: stringserverMessage: '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: PageServerLoadload: 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: stringserverMessage: '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: anydata }) {
return {
serverMessage: anyserverMessage: data: anydata.serverMessage,
universalMessage: stringuniversalMessage: '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: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ data: Record<string, any> | nullContains the data returned by the route’s server load function (in +layout.server.js or +page.server.js), if any.
data }) => {
return {
serverMessage: anyserverMessage: data: Record<string, any> | nullContains the data returned by the route’s server load function (in +layout.server.js or +page.server.js), if any.
data.serverMessage,
universalMessage: stringuniversalMessage: '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,
urlest 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: anyroute }) {
var console: ConsoleThe 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 importing the node:console module.
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: anyroute.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: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = ({ route: {
id: string | null;
}
Info about the current route
route }) => {
var console: ConsoleThe 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 importing the node:console module.
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 | nullThe 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
cookieetauthorizationde la requête de page. - Elle peut faire des requêtes relatives au serveur (normallement,
fetchrequiert 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,jsonetarrayBufferde 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
fetchnatif du navigateur plutôt que lefetchdeload, en voici la raison.
/** @type {import('./$types').PageLoad} */
export async function function load({ fetch, params }: {
fetch: any;
params: any;
}): Promise<{
item: any;
}>
load({ fetch: anyfetch, params: anyparams }) {
const const res: anyres = await fetch: anyfetch(`/api/items/${params: anyparams.id}`);
const const item: anyitem = await const res: anyres.json();
return { item: anyitem };
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = 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: Responseres = 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: anyitem = await const res: Responseres.Body.json(): Promise<any>json();
return { item: anyitem };
};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: CookiesGet or set cookies related to the current request
cookies }) {
const const sessionid: string | undefinedsessionid = cookies: CookiesGet or set cookies related to the current request
cookies.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefinedGets 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 | undefinedsessionid)
};
}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: LayoutServerLoadload: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad = async ({ cookies: CookiesGet or set cookies related to the current request
cookies }) => {
const const sessionid: string | undefinedsessionid = cookies: CookiesGet or set cookies related to the current request
cookies.Cookies.get: (name: string, opts?: CookieParseOptions) => string | undefinedGets 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 | undefinedsessionid)
};
};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: anyfetch, setHeaders: anysetHeaders }) {
const const url: "https://cms.example.com/products.json"url = `https://cms.example.com/products.json`;
const const response: anyresponse = await fetch: anyfetch(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: anysetHeaders({
age: anyage: const response: anyresponse.headers.get('age'),
'cache-control': const response: anyresponse.headers.get('cache-control')
});
return const response: anyresponse.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: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = 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>) => voidIf 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: Responseresponse = 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>) => voidIf 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 | nullage: const response: Responseresponse.Response.headers: Headersheaders.Headers.get(name: string): string | nullget('age'),
'cache-control': const response: Responseresponse.Response.headers: Headersheaders.Headers.get(name: string): string | nullget('cache-control')
});
return const response: Responseresponse.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: numbera: 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: LayoutLoadload: 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: numbera: 1 };
};/** @type {import('./$types').LayoutLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
b: any;
}>
load({ parent: anyparent }) {
const { const a: anya } = await parent: anyparent();
return { b: anyb: const a: anya + 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: LayoutLoadload: 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: anya } = 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: anyb: const a: anya + 1 };
};/** @type {import('./$types').PageLoad} */
export async function function load({ parent }: {
parent: any;
}): Promise<{
c: any;
}>
load({ parent: anyparent }) {
const { const a: anya, const b: anyb } = await parent: anyparent();
return { c: anyc: const a: anya + const b: anyb };
}import type { type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = 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: anya, const b: anyb } = 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: anyc: const a: anya + const b: anyb };
};<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
loadde+page.jsreçoit la donnée fusionnée des deux fonctionsloadde 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: anymeta: { ...const parentData: Record<string, any>parentData.meta, ...const data: {
meta: any;
}
data.meta: anymeta }
};
}import type { type PageLoad = (event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageLoad } from './$types';
export const const load: PageLoadload: type PageLoad = (event: LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>PageLoad = 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: anymeta: { ...const parentData: Record<string, any>parentData.meta, ...const data: {
meta: any;
}
data.meta: anymeta }
};
};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.LocalsContains custom data that was added to the request within the server handle hook.
locals }) {
if (!locals: App.LocalsContains 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.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: booleanisAdmin) {
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: LayoutServerLoadload: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad = ({ locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals }) => {
if (!locals: App.LocalsContains 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.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: {
name: string;
isAdmin: boolean;
}
user.isAdmin: booleanisAdmin) {
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
throwl’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): neverRedirect 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.LocalsContains custom data that was added to the request within the server handle hook.
locals }) {
if (!locals: App.LocalsContains 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): neverRedirect 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): neverRedirect 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: LayoutServerLoadload: type LayoutServerLoad = (event: ServerLoadEvent<Record<string, any>, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>LayoutServerLoad = ({ locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals }) => {
if (!locals: App.LocalsContains 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): neverRedirect 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
throwleredirectvous-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: PageServerLoadload: 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: anyfetch }) {
const const ok_manual: Promise<never>ok_manual = var Promise: PromiseConstructorRepresents 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: anyok_fetch: fetch: anyfetch('/fetch/that/could/fail'),
dangerous_unhandled: Promise<never>dangerous_unhandled: var Promise: PromiseConstructorRepresents 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: PageServerLoadload: 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: PromiseConstructorRepresents 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: PromiseConstructorRepresents 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
loaduniverselle 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
setHeadersou 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: PageServerLoadload: 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: LayoutServerLoadload: 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: anyuntrack, url: anyurl }) {
// arrête le suivi de url.pathname afin qu'un changement de path de
// déclenche pas une ré-exécution
if (untrack: anyuntrack(() => url: anyurl.pathname === '/')) {
return { message: stringmessage: '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: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = async ({ untrack: <T>(fn: () => T) => TUse 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: URLThe 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) => booleanUse 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: URLThe URL of the current page
url.URL.pathname: stringpathname === '/')) {
return { message: stringmessage: '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: anyfetch, depends: anydepends }) {
// load est ré-exécutée lorsque `invalidate('https://api.example.com/random-number') est
// appelée...
const const response: anyresponse = await fetch: anyfetch('https://api.example.com/random-number');
// ... ou lorsque `invalidate('app:random') est appelée
depends: anydepends('app:random');
return {
number: anynumber: await const response: anyresponse.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: PageLoadload: type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
type PageLoad = (event: Kit.LoadEvent<Record<string, any>, Record<string, any> | null, Record<string, any>, string | null>) => MaybePromise<void | Record<string, any>>
PageLoad = 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}`>) => voidThis 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 invalidated 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: Responseresponse = 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}`>) => voidThis 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 invalidated 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: anynumber: await const response: Responseresponse.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
paramsdont la valeur a changé - Elle référence une propriété de l’
url(commeurl.pathnameouurl.search) dont la valeur a changé. Les propriétés derequest.urlne 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.searchParamsaura le même effet que lireurl.search. - Elle exécute
await parent()et une fonctionloadparente a été ré-exécutée - Une fonction
loadenfante exécuteawait parent()et est ré-exécutée, et le parent est une fonctionloadde serveur - Elle déclare une dépendance sur une URL spécifique via
fetch(loaduniverselles uniquement) oudepends, et cette URL a été déclarée comme obsolète avecinvalidate(url) - Toutes les fonctions
loadactives 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
loadde 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
loadde layout et de page sont exécutées de manière concurrente à moins queawait parent()soit utilisé. Si une fonctionloadde layout lève une exception, la fonctionloadde 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
loadne soit exécutée - Utilisez des vérifications d’authentification directement dans les fonctions
loadde+page.server.jspour 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): neverRedirect 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(): RequestEventReturns the current RequestEvent. Can be used inside server hooks, server load functions, actions, and endpoints (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(): UserrequireLogin() {
const { const locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals, const url: URLThe requested URL.
url } = function getRequestEvent(): RequestEventReturns the current RequestEvent. Can be used inside server hooks, server load functions, actions, and endpoints (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.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: User | undefineduser) {
const const redirectTo: stringredirectTo = const url: URLThe requested URL.
url.URL.pathname: stringpathname + const url: URLThe requested URL.
url.URL.search: stringsearch;
const const params: URLSearchParamsparams = new var URLSearchParams: new (init?: string[][] | Record<string, string> | string | URLSearchParams) => URLSearchParams
URLSearchParams class is a global reference for import { URLSearchParams } from 'node:url'
https://nodejs.org/api/url.html#class-urlsearchparams
URLSearchParams({ redirectTo: stringredirectTo });
function redirect(status: 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | ({} & number), location: string | URL): neverRedirect 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: URLSearchParamsparams}`);
}
return const locals: App.LocalsContains custom data that was added to the request within the server handle hook.
locals.App.Locals.user?: Useruser;
}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(): UserrequireLogin } from '$lib/server/auth';
export function function load(): {
message: string;
}
load() {
const const user: Useruser = function requireLogin(): UserrequireLogin();
// `user` est garanti d'être un objet user ici, car sinon `requireLogin`
// provoquerait une redirection et nous ne pourrions pas arriver ici
return {
message: stringmessage: `bonjour ${const user: Useruser.User.name: stringname}!`
};
}En savoir plus
Modifier cette page sur Github llms.txt