svelte-core-bestpractices

Par sveltejs · ai-tools

Guide pour écrire du code Svelte rapide, robuste et moderne. Chargez cette skill dès que vous travaillez sur un projet Svelte et que vous devez écrire, modifier ou analyser un composant ou module Svelte. Couvre la réactivité, la gestion des événements, le styling, l'intégration avec des bibliothèques, et bien plus encore.

npx skills add https://github.com/sveltejs/ai-tools --skill svelte-core-bestpractices

$state

Utilisez la rune $state uniquement pour les variables qui doivent être réactives — autrement dit, les variables qui déclenchent une mise à jour dans $effect, $derived ou une expression template. Tout le reste peut être une variable normale.

Les objets et tableaux ($state({...}) ou $state([...])) sont rendus profondément réactifs, ce qui signifie que les mutations déclencheront des mises à jour. Cela a un coût : en échange d'une réactivité fine, les objets doivent être proxifiés, ce qui a un surcoût de performance. Dans les cas où vous avez affaire à de grands objets qui ne sont jamais que réassignés (plutôt que mutés), utilisez $state.raw à la place. C'est souvent le cas avec les réponses API, par exemple.

$derived

Pour calculer quelque chose à partir de l'état, utilisez $derived plutôt que $effect :

// faites ceci
let square = $derived(num * num);

// ne faites pas ceci
let square;

$effect(() => {
    square = num * num;
});

[!NOTE] $derived reçoit une expression, pas une fonction. Si vous avez besoin d'utiliser une fonction (parce que l'expression est complexe, par exemple) utilisez $derived.by.

Les dérivés sont modifiables — vous pouvez leur assigner une valeur, tout comme $state, sauf qu'ils seront réévalués quand leur expression change.

Si l'expression du dérivé est un objet ou un tableau, il sera retourné tel quel — il n'est pas rendu profondément réactif. Vous pouvez cependant utiliser $state à l'intérieur de $derived.by dans les rares cas où vous en auriez besoin.

$effect

Les effets sont une échappatoire et doivent être évités dans la plupart des cas. En particulier, évitez de mettre à jour l'état à l'intérieur des effets.

  • Si vous avez besoin de synchroniser l'état avec une bibliothèque externe comme D3, il est souvent plus propre d'utiliser {@attach ...}
  • Si vous avez besoin d'exécuter du code en réponse à une interaction utilisateur, mettez le code directement dans un gestionnaire d'événement ou utilisez un function binding selon le cas
  • Si vous avez besoin de enregistrer des valeurs à des fins de débogage, utilisez $inspect
  • Si vous avez besoin d'observer quelque chose d'externe à Svelte, utilisez createSubscriber

N'enrobez jamais le contenu d'un effet dans if (browser) {...} ou similaire — les effets ne s'exécutent pas sur le serveur.

$props

Traitez les props comme si elles allaient changer. Par exemple, les valeurs qui dépendent des props doivent généralement utiliser $derived :

// @errors: 2451
let { type } = $props();

// faites ceci
let color = $derived(type === 'danger' ? 'red' : 'green');

// ne faites pas ceci — `color` ne sera pas mise à jour si `type` change
let color = type === 'danger' ? 'red' : 'green';

$inspect.trace

$inspect.trace est un outil de débogage pour la réactivité. Si quelque chose ne se met pas à jour correctement ou s'exécute plus qu'il ne le devrait, vous pouvez ajouter $inspect.trace(label) comme première ligne d'un $effect ou $derived.by (ou de toute fonction qu'ils appellent) pour tracer leurs dépendances et découvrir laquelle a déclenché une mise à jour.

Événements

Tout attribut d'élément commençant par on est traité comme un gestionnaire d'événement :

<button onclick={() => {...}}>click me</button>

<!-- le raccourci d'attribut fonctionne aussi -->
<button {onclick}>...</button>

<!-- tout comme les attributs propagés -->
<button {...props}>...</button>

Si vous avez besoin d'attacher des écouteurs à window ou document vous pouvez utiliser <svelte:window> et <svelte:document> :

<svelte:window onkeydown={...} />
<svelte:document onvisibilitychange={...} />

Évitez d'utiliser onMount ou $effect pour cela.

Snippets

Les snippets sont un moyen de définir des blocs de markup réutilisables qui peuvent être instanciés avec la balise {@render ...}, ou passés aux composants en tant que props. Ils doivent être déclarés dans le template.

{#snippet greeting(name)}
    <p>hello {name}!</p>
{/snippet}

{@render greeting('world')}

[!NOTE] Les snippets déclarés au niveau supérieur d'un composant (c'est-à-dire pas à l'intérieur d'éléments ou de blocs) peuvent être référencés à l'intérieur de <script>. Un snippet qui ne référence pas l'état du composant est également disponible dans un <script module>, auquel cas il peut être exporté pour utilisation par d'autres composants.

Blocs each

Préférez utiliser des blocs each avec clé — cela améliore les performances en permettant à Svelte d'insérer ou supprimer chirurgicalement des éléments plutôt que de mettre à jour le DOM appartenant aux éléments existants.

[!NOTE] La clé doit identifier uniquement l'objet. N'utilisez pas l'index comme clé.

Évitez de destructurer si vous avez besoin de muter l'élément (avec quelque chose comme bind:value={item.count}, par exemple).

Utiliser des variables JavaScript en CSS

Si vous avez une variable JS que vous voulez utiliser à l'intérieur du CSS, vous pouvez définir une propriété personnalisée CSS avec la directive style:.

<div style:--columns={columns}>...</div>

Vous pouvez alors référencer var(--columns) à l'intérieur du <style> du composant.

Styliser les composants enfants

Le CSS dans le <style> d'un composant est limité à ce composant. Si un composant parent doit contrôler les styles de l'enfant, la manière préférée est d'utiliser les propriétés personnalisées CSS :

<!-- Parent.svelte -->
<Child --color="red" />

<!-- Child.svelte -->
<h1>Hello</h1>

<style>
    h1 {
        color: var(--color);
    }
</style>

Si cela est impossible (par exemple, le composant enfant provient d'une bibliothèque) vous pouvez utiliser :global pour remplacer les styles :

<div>
    <Child />
</div>

<style>
    div :global {
        h1 {
            color: red;
        }
    }
</style>

Context

Envisagez d'utiliser context au lieu de déclarer l'état dans un module partagé. Cela limitera l'état à la partie de l'application qui en a besoin, et éliminera la possibilité qu'il ne s'échappe entre les utilisateurs lors du rendu côté serveur.

Utilisez createContext plutôt que setContext et getContext, car il fournit la sécurité des types.

Async Svelte

Si vous utilisez la version 5.36 ou supérieure, vous pouvez utiliser les await expressions et hydratable pour utiliser les promesses directement à l'intérieur des composants. Notez que celles-ci nécessitent que l'option experimental.async soit activée dans svelte.config.js car elles ne sont pas encore considérées comme totalement stables.

Éviter les fonctionnalités héritées

Utilisez toujours le mode runes pour le nouveau code, et évitez les fonctionnalités qui ont des remplaçants plus modernes :

  • utilisez $state au lieu de la réactivité implicite (par ex. let count = 0; count += 1)
  • utilisez $derived et $effect au lieu des assignations et statements $: (mais utilisez les effets uniquement quand il n'y a pas de meilleure solution)
  • utilisez $props au lieu de export let, $$props et $$restProps
  • utilisez onclick={...} au lieu de on:click={...}
  • utilisez {#snippet ...} et {@render ...} au lieu de <slot>, $$slots et <svelte:fragment>
  • utilisez <DynamicComponent> au lieu de <svelte:component this={DynamicComponent}>
  • utilisez import Self from './ThisComponent.svelte' et <Self> au lieu de <svelte:self>
  • utilisez les classes avec champs $state pour partager la réactivité entre composants, au lieu d'utiliser les stores
  • utilisez {@attach ...} au lieu de use:action
  • utilisez des tableaux et objets de style clsx dans les attributs class, au lieu de la directive class:

Skills similaires