Qu’est-ce que Svelte ?
Svelte est un framework de composants avec une particularité : c’est un compilateur. Au lieu de livrer un runtime qui interprète vos composants dans le navigateur, Svelte les analyse lors de l’étape de build et génère du JavaScript pur qui met à jour le DOM directement. Il n’y a pas de virtual DOM et quasiment aucun code de framework dans le bundle final.
Cette conception transforme l’expérience développeur. La réactivité est intégrée au langage, les styles sont scopés par défaut et les transitions sont natives, ce qui permet d’obtenir des composants concis. Le compromis est la nécessité d’une étape de build, mais avec l’outillage moderne, c’est désormais une norme.
Composants monofichiers
Un composant Svelte est un fichier .svelte comprenant un bloc de script, du markup et des styles optionnels dont la portée est limitée au composant.
<!-- Card.svelte -->
<script>
let { title, children } = $props();
</script>
<article class="card">
<h3>{title}</h3>
{@render children?.()}
</article>
<style>
.card {
border-radius: 1rem;
padding: 1.5rem;
}
</style>
Par défaut, les styles d’un composant sont isolés, ce qui empêche la règle .card de s’appliquer ailleurs. $props() lit les props transmises par le parent, et les snippets (children) permettent à un parent de transmettre du markup à un enfant.
La réactivité avec les runes
Svelte 5 a introduit les runes, des primitives explicites qui rendent la réactivité prévisible. $state déclare l’état réactif, $derived calcule des valeurs, et $effect exécute des effets de bord.
<!-- Search.svelte -->
<script>
let query = $state("");
let results = $state([]);
let hasResults = $derived(results.length > 0);
$effect(() => {
if (!query) return;
const controller = new AbortController();
fetch(`/api/search?q=${query}`, { signal: controller.signal })
.then((r) => r.json())
.then((data) => (results = data))
.catch(() => {});
return () => controller.abort();
});
</script>
<input bind:value={query} placeholder="Search" />
{#if hasResults}
<ul>
{#each results as item (item.id)}
<li>{item.name}</li>
{/each}
</ul>
{/if}
Les runes fonctionnent également dans les fichiers .svelte.js et .svelte.ts, vous permettant ainsi d’extraire la logique réactive dans des modules réutilisables, à la manière des hooks personnalisés de React.
Props, événements et snippets
Les props descendent dans la hiérarchie et sont déclarées avec $props(). Au lieu d’un système d’événements spécifique, Svelte 5 utilise des callback props pour la communication de l’enfant vers le parent.
<!-- Child.svelte -->
<script>
let { label, onselect } = $props();
</script>
<button onclick={() => onselect(label)}>{label}</button>
<!-- Parent.svelte -->
<Child label="Save" onselect={(value) => save(value)} />
Les snippets remplacent les slots pour les régions de marquage réutilisables, et {@render} les insère là où vous le souhaitez.
Flux de contrôle
Svelte propose des blocs de template dédiés pour les conditionnels et les boucles, et le bloc #each prend en charge une expression avec clé pour des mises à jour efficaces.
<!-- list.svelte -->
{#if users.length > 0}
<ul>
{#each users as user (user.id)}
<li>{user.name}</li>
{/each}
</ul>
{:else}
<p>No users yet.</p>
{/if}
Comme le compilateur connaît la structure, ces blocs génèrent des opérations DOM ciblées plutôt qu’une phase de réconciliation générique.
Stores et état partagé
Pour l’état partagé entre plusieurs composants, Svelte propose les stores : un store writable détient une valeur et notifie ses abonnés, tandis que readable et derived couvrent d’autres cas de figure.
// counter.js
import { writable, derived } from "svelte/store";
export const count = writable(0);
export const double = derived(count, ($count) => $count * 2);
<!-- Display.svelte -->
<script>
import { count, double } from "./counter.js";
</script>
<p>{$count} doubled is {$double}</p>
Le préfixe $ gère automatiquement l’abonnement et le désabonnement pour vous. Avec les runes, un module .svelte.js exportant $state peut accomplir la même chose sans utiliser l’API des stores, une approche privilégiée par de nombreux nouveaux projets pour les valeurs globales de l’application.
Transitions et animations
Le mouvement est intégré nativement. Les directives transition, animate et in/out permettent d’ajouter des animations sans avoir recours à une bibliothèque externe.
<!-- toast.svelte -->
<script>
import { fade, fly } from "svelte/transition";
let visible = $state(false);
</script>
<button onclick={() => (visible = !visible)}>Toggle</button>
{#if visible}
<div transition:fly={{ y: 20, duration: 200 }}>
Saved!
</div>
{/if}
Comme les transitions sont compilées, elles sont performantes et compatibles avec le tree-shaking. De plus, elles respectent les préférences de réduction du mouvement de l’utilisateur lorsque vous utilisez les helpers intégrés.
SvelteKit
SvelteKit est le framework d’application officiel. Il ajoute le routage basé sur les fichiers, le rendu serveur, le chargement de données et les actions de formulaire par-dessus Svelte.
src/routes/
├── +page.svelte # a page
├── +layout.svelte # shared layout
├── about/+page.svelte # /about
└── blog/[slug]/+page.js # load data for /blog/:slug
Si vous construisez plus qu’un simple widget, SvelteKit est le point de départ recommandé. Il gère les conventions dont chaque application réelle a besoin, vous permettant ainsi de vous concentrer sur les fonctionnalités.
Bonnes pratiques
- Utilisez les runes (
$state,$derived,$effect) dans votre nouveau code. - Privilégiez
$derivedpour les valeurs calculées et réservez$effectpour les effets de bord. - Gardez vos composants concis et extrayez la logique réutilisable dans des modules
.svelte.js. - Utilisez des blocs
{#each}avec des clés lorsque les éléments peuvent être réordonnés. - Scopez vos styles par défaut et évitez
:globalsauf si nécessaire. - Partagez l’état entre plusieurs composants via des stores ou un module réactif.
- Démarrez vos nouvelles applications avec SvelteKit plutôt que de configurer vous-même votre build.
Erreurs courantes
- Utiliser
$effectpour calculer une valeur que$deriveddevrait gérer. - Oublier la clé dans
{#each}, ce qui casse les mises à jour de listes. - Muter une propriété imbriquée d’un objet
$stated’une manière qui contourne la réactivité dans les anciens modèles. - Recourir à un store global alors qu’un état local suffirait.
- Supposer que Svelte n’a aucun runtime — il y en a un, bien que léger.
- Négliger l’accessibilité parce que le compilateur permet d’écrire le markup très rapidement.
Et après ?
Svelte est un moyen rapide et élégant de construire des interfaces, et SvelteKit le transforme en un framework d’application complet. Comparez l’approche par compilation avec React et Vue, et continuez à perfectionner votre JavaScript. Ensuite, créez une petite application avec un store et une transition pour ressentir la différence.