Avant qu'un composant [`+page.svelte`](routing#page-page.svelte) (et ses composants [`+layout.svelte`](routing#layout-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 [!VO]Page data 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` : ```js /// file: src/routes/blog/[slug]/+page.js /** @type {import('./$types').PageLoad} */ export function load({ params }) { return { post: { title: `Titre pour ${params.slug}`, content: `Contenu pour ${params.slug}` } }; } ``` ```svelte

{data.post.title}

{@html data.post.content}
``` > [!LEGACY] > Avant la version 2.16.0, les props d'une page et d'un layout devaient être typées individuellement > : > ```js > /// file: +page.svelte > /** @type {{ data: import('./$types').PageData }} */ > let { data } = $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](page-options#ssr)). 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 : ```js /// file: src/routes/blog/[slug]/+page.server.js // @filename: ambient.d.ts declare module '$lib/server/database' { export function getPost(slug: string): Promise<{ title: string, content: string }> } // @filename: index.js // ---cut--- import * as db from '$lib/server/database'; /** @type {import('./$types').PageServerLoad} */ export async function load({ params }) { return { post: await db.getPost(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](load#Universal-vs-server). ## Données de layout [!VO]Layout data Vos fichiers `+layout.svelte` peuvent aussi charger des données, via `+layout.js` ou `+layout.server.js`. ```js /// file: src/routes/blog/[slug]/+layout.server.js // @filename: ambient.d.ts declare module '$lib/server/database' { export function getPostSummaries(): Promise> } // @filename: index.js // ---cut--- import * as db from '$lib/server/database'; /** @type {import('./$types').LayoutServerLoad} */ export async function load() { return { posts: await db.getPostSummaries() }; } ``` ```svelte
{@render children()}
``` > [!LEGACY] > `LayoutProps` a été ajouté dans la version 2.16.0. Dans les versions antérieures, les propriétés > devaient être typées individuellement : > ```js > /// file: +layout.svelte > /** @type {{ data: import('./$types').LayoutData, children: Snippet }} */ > let { data, children } = $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. ```svelte /// file: src/routes/blog/[slug]/+page.svelte

{data.post.title}

{@html data.post.content}
+++{#if next}

Article suivant : {next.title}

{/if}+++ ``` > [!NOTE] Si plusieurs fonctions `load` renvoient des données avec la même clé, la dernière "gagne" > — le résultat d'une fonction `load` de layout renvoyant `{ a: 1, b: 2}` et d'une fonction `load` > 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` : ```svelte {page.data.title} ``` L'information de typage de `page.data` est fournie par `App.PageData`. > [!LEGACY] > `$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 de `page` ayant la > même interface, et vous pouvez vous y abonner avec, par exemple, `$page.data.title`. ## Universel vs serveur [!VO]Universal vs server Comme nous l'avons vu, il y a deux types de fonctions `load` : * les fichiers `+page.js` et `+layout.js` exportent des fonctions `load` _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 fonctions `load` 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 ? [!VO]When does which load function run? 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`](#Making-fetch-requests). Toutes les invocations suivantes de fonctions `load` universelles vont se produire dans le navigateur. Vous pouvez personnaliser ce comportement via les [options de page](page-options). Si vous désactivez le [rendu côté serveur](page-options#ssr), 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](page-options#prerender) la page — dans ce cas, elle sera invoquée au moment de la compilation. ### Entrées [!VO]Input 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 [!VO]Output 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](https://github.com/rich-harris/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](#Streaming-with-promises), auquel cas elles seront streamées vers les navigateurs. ### Quand utiliser quoi [!VO]When to use which 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`) : ```js /// file: src/routes/+page.server.js /** @type {import('./$types').PageServerLoad} */ export async function load() { return { serverMessage: 'bonjour depuis la fonction load de serveur' }; } ``` ```js /// file: src/routes/+page.js // @errors: 18047 /** @type {import('./$types').PageLoad} */ export async function load({ data }) { return { serverMessage: data.serverMessage, universalMessage: 'bonjour depuis la fonction load universelle' }; } ``` ## Utiliser les données d'URL [!VO]Using URL data 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`](https://developer.mozilla.org/fr/docs/Web/API/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`](https://developer.mozilla.org/fr/docs/Web/API/URLSearchParams)). `url.hash` n'est pas accessible pendant l'exécution de `load`, car il n'est pas disponible sur le serveur. > [!NOTE] 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](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` : ```js /// file: src/routes/a/[b]/[...c]/+page.js /** @type {import('./$types').PageLoad} */ export function load({ route }) { console.log(route.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 : ```json { "b": "x", "c": "y/z" } ``` ## Faire des requêtes avec fetch [!VO]Making fetch requests 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](https://developer.mozilla.org/fr/docs/Web/API/fetch) 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` et `authorization` 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` et `arrayBuffer` de l'objet `Response`. Notez que les en-têtes ne seront _pas_ sérialisées, à moins d'être explicitement incluses via [`filterSerializedResponseHeaders`](hooks#Server-hooks-handle). - 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 le `fetch` de `load`, en voici la raison. ```js /// file: src/routes/items/[id]/+page.js /** @type {import('./$types').PageLoad} */ export async function load({ fetch, params }) { const res = await fetch(`/api/items/${params.id}`); const item = await res.json(); return { item }; } ``` ## Cookies Une fonction `load` de serveur peut récupérer et définir des [`cookies`](@sveltejs-kit#Cookies). ```js /// file: src/routes/+layout.server.js // @filename: ambient.d.ts declare module '$lib/server/database' { export function getUser(sessionid: string | undefined): Promise<{ name: string, avatar: string }> } // @filename: index.js // ---cut--- import * as db from '$lib/server/database'; /** @type {import('./$types').LayoutServerLoad} */ export async function load({ cookies }) { const sessionid = cookies.get('sessionid'); return { user: await db.getUser(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`](hooks#Server-hooks-handleFetch) pour contourner le problème. ## En-têtes [!VO]Headers 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 : ```js // @errors: 2322 1360 /// file: src/routes/products/+page.js /** @type {import('./$types').PageLoad} */ export async function load({ fetch, setHeaders }) { const url = `https://cms.example.com/products.json`; const response = await fetch(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({ age: response.headers.get('age'), 'cache-control': response.headers.get('cache-control') }); return response.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 [!VO]Using parent data 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()` : ```js /// file: src/routes/+layout.js /** @type {import('./$types').LayoutLoad} */ export function load() { return { a: 1 }; } ``` ```js /// file: src/routes/abc/+layout.js /** @type {import('./$types').LayoutLoad} */ export async function load({ parent }) { const { a } = await parent(); return { b: a + 1 }; } ``` ```js /// file: src/routes/abc/+page.js /** @type {import('./$types').PageLoad} */ export async function load({ parent }) { const { a, b } = await parent(); return { c: a + b }; } ``` ```svelte

{data.a} + {data.b} = {data.c}

``` > [!NOTE] Notez que la fonction `load` de `+page.js` reçoit la donnée fusionnée des deux fonctions > `load` 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. ```js /// file: +page.js // @filename: ambient.d.ts declare function getData(params: Record): Promise<{ meta: any }> // @filename: index.js // ---cut--- /** @type {import('./$types').PageLoad} */ export async function load({ params, parent }) { ---const parentData = await parent();--- const data = await getData(params); +++const parentData = await parent();+++ return { ...data, meta: { ...parentData.meta, ...data.meta } }; } ``` ## Erreurs [!VO]Errors Si une erreur est jetée lors d'une fonction `load`, la page [`+error.svelte`](routing#error) la plus proche sera rendue. Pour les erreurs [_prévues_](errors#Expected-errors), utilisez l'utilitaire `error` importé depuis `@sveltejs/kit` pour préciser le statut HTTP et un message optionnel : ```js /// file: src/routes/admin/+layout.server.js // @filename: ambient.d.ts declare namespace App { interface Locals { user?: { name: string; isAdmin: boolean; } } } // @filename: index.js // ---cut--- import { error } from '@sveltejs/kit'; /** @type {import('./$types').LayoutServerLoad} */ export function load({ locals }) { if (!locals.user) { error(401, 'non identifié'); } if (!locals.user.isAdmin) { 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_](errors#Unexpected-errors) est levée, SvelteKit va exécuter le hook [`handleError`](hooks#Shared-hooks-handleError) et la traiter comme une erreur 500 Internal Error. > [!NOTE] [Dans SvelteKit > 1.x](migrating-to-sveltekit-2#redirect-and-error-are-no-longer-thrown-by-you), vous deviez `throw` > l'erreur vous-même. ## Redirections [!VO]Redirects 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. ```js /// file: src/routes/user/+layout.server.js // @filename: ambient.d.ts declare namespace App { interface Locals { user?: { name: string; } } } // @filename: index.js // ---cut--- import { redirect } from '@sveltejs/kit'; /** @type {import('./$types').LayoutServerLoad} */ export function load({ locals }) { if (!locals.user) { redirect(307, '/login'); } } ``` > [!NOTE] N'utilisez pas `redirect()` au sein d'un block `try {...}`, puisque la redirection va > immédiatement déclencher l'exécution du `catch`. Dans le navigateur, vous pouvez naviguer programmatiquement en dehors d'une fonction `load` en utilisant [`goto`]($app-navigation#goto) importé depuis [`$app/navigation`]($app-navigation). > [!NOTE] [Dans SvelteKit > 1.x](migrating-to-sveltekit-2#redirect-and-error-are-no-longer-thrown-by-you) vous deviez `throw` > le `redirect` vous-même. ## Streamer grâce aux promesses [!VO]Streaming with promises 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 : ```js /// file: src/routes/blog/[slug]/+page.server.js // @filename: ambient.d.ts declare global { const loadPost: (slug: string) => Promise<{ title: string, content: string }>; const loadComments: (slug: string) => Promise<{ content: string }>; } export {}; // @filename: index.js // ---cut--- /** @type {import('./$types').PageServerLoad} */ export async function load({ 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: loadComments(params.slug), post: await loadPost(params.slug) }; } ``` C'est utile notamment pour créer des états de chargement, par exemple : ```svelte

{data.post.title}

{@html data.post.content}
{#await data.comments} Chargement des commentaires... {:then comments} {#each comments as comment}

{comment.content}

{/each} {:catch error}

erreur lors du chargement des commentaires : {error.message}

{/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. ```js /// file: src/routes/+page.server.js /** @type {import('./$types').PageServerLoad} */ export function load({ fetch }) { const ok_manual = Promise.reject(); ok_manual.catch(() => {}); return { ok_manual, ok_fetch: fetch('/fetch/that/could/fail'), dangerous_unhandled: Promise.reject() }; } ``` > [!NOTE] 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. > [!NOTE] 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. > [!NOTE] 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. > [!NOTE] [Avec SvelteKit 1.x](migrating-to-sveltekit-2#Top-level-promises-are-no-longer-awaited) > les promesses créées à la racine étaient automatiquement attendues, et uniquement les promesses > imbriquées étaient streamées. ## Chargement parallèle [!VO]Parallel loading 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 [!VO]Rerunning load functions 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... ```js /// file: src/routes/blog/[slug]/+page.server.js // @filename: ambient.d.ts declare module '$lib/server/database' { export function getPost(slug: string): Promise<{ title: string, content: string }> } // @filename: index.js // ---cut--- import * as db from '$lib/server/database'; /** @type {import('./$types').PageServerLoad} */ export async function load({ params }) { return { post: await db.getPost(params.slug) }; } ``` ```js /// file: src/routes/blog/[slug]/+layout.server.js // @filename: ambient.d.ts declare module '$lib/server/database' { export function getPostSummaries(): Promise> } // @filename: index.js // ---cut--- import * as db from '$lib/server/database'; /** @type {import('./$types').LayoutServerLoad} */ export async function load() { return { posts: await db.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](#Streaming-with-promises) 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 [!VO]Untracking dependencies 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` : ```js /// file: src/routes/+page.js /** @type {import('./$types').PageLoad} */ export async function load({ untrack, url }) { // arrête le suivi de url.pathname afin qu'un changement de path de // déclenche pas une ré-exécution if (untrack(() => url.pathname === '/')) { return { message: 'Bienvenue !' }; } } ``` ### Invalidation manuelle [!VO]Manual invalidation Vous pouvez également ré-exécuter des fonctions `load` s'appliquant à la page actuelle en utilisant [`invalidate(url)`]($app-navigation#invalidate), ce qui ré-exécute toutes les fonctions `load` qui dépendent d'`url`, ou [`invalidateAll()`]($app-navigation#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]` : ```js /// file: src/routes/random-number/+page.js /** @type {import('./$types').PageLoad} */ export async function load({ fetch, depends }) { // load est ré-exécutée lorsque `invalidate('https://api.example.com/random-number') est // appelée... const response = await fetch('https://api.example.com/random-number'); // ... ou lorsque `invalidate('app:random') est appelée depends('app:random'); return { number: await response.json() }; } ``` ```svelte

nombre aléatoire : {data.number}

``` ### Quand est-ce que les fonctions load sont ré-exécutées ? [!VO]When do load functions rerun? 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` (comme `url.pathname` ou `url.search`) dont la valeur a changé. Les propriétés de `request.url` ne sont _pas_ suivies - Elle exécute `url.searchParams.get(...)`, `url.searchParams.getAll(...)` ou `url.searchParams.has(...)` et le paramètre en question a changé. Lire d'autres propriétés de `url.searchParams` aura le même effet que lire `url.search`. - Elle exécute `await parent()` et une fonction `load` parente a été ré-exécutée - Une fonction `load` enfante exécute `await parent()` et est ré-exécutée, et le parent est une fonction `load` de serveur - Elle déclare une dépendance sur une URL spécifique via [`fetch`](#Making-fetch-requests) (`load` universelles uniquement) ou [`depends`](@sveltejs-kit#LoadEvent), et cette URL a été déclarée comme obsolète avec [`invalidate(url)`]($app-navigation#invalidate) - Toutes les fonctions `load` actives ont été ré-exécutées de manière forcée avec [`invalidateAll()`]($app-navigation#invalidateAll) `params` et `url` peuvent changer en réaction à un clic sur un lien ``, une [interaction de formulaire](form-actions#GET-vs-POST), une invocation de [`goto`]($app-navigation#goto), ou une redirection [`redirect`](@sveltejs-kit#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`]($app-navigation#afterNavigate), et/ou entourer votre composant d'un bloc [`{#key ...}`](../svelte/key). ## Implications pour l'authentification [!VO]Implications for authentication 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 ?)](load#Rerunning-load-functions-When-do-load-functions-rerun) - Les fonctions `load` de layout et de page sont exécutées de manière concurrente à moins que `await parent()` soit utilisé. Si une fonction `load` de layout lève une exception, la fonction `load` 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](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` [!VO]Using `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`]($app-server#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 : ```js /// file: src/lib/server/auth.js // @filename: ambient.d.ts interface User { name: string; } declare namespace App { interface Locals { user?: User; } } // @filename: index.ts // ---cut--- import { redirect } from '@sveltejs/kit'; import { getRequestEvent } from '$app/server'; export function requireLogin() { const { locals, url } = getRequestEvent(); // assume `locals.user` is populated in `handle` if (!locals.user) { const redirectTo = url.pathname + url.search; const params = new URLSearchParams({ redirectTo }); redirect(307, `/login?${params}`); } return locals.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 : ```js /// file: +page.server.js // @filename: ambient.d.ts declare module '$lib/server/auth' { interface User { name: string; } export function requireLogin(): User; } // @filename: index.ts // ---cut--- import { requireLogin } from '$lib/server/auth'; export function load() { const 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: `bonjour ${user.name}!` }; } ``` ## En savoir plus [!VO]Further reading - [Tutoriel : Charger des données](/tutorial/kit/page-data) - [Tutoriel : Erreurs and redirections](/tutorial/kit/error-basics) - [Tutoriel : Chargement avancé](/tutorial/kit/await-parent)