Cours Svelte et SvelteKit · Module 2: Composants

Yggdrasil - L'arbre des composants

3 min de lecture ·
Dans cette leçon3

Bienvenue à Yggdrasil, le grand arbre-monde qui relie les neuf royaumes ! En Svelte, les composants sont comme les branches de cet arbre : chacune peut avoir ses propres sous-branches (composants enfants), et ensemble elles forment une structure puissante.

Structure d'un composant Svelte

Chaque fichier .svelte est un composant séparé :

<!-- WorldTree.svelte -->
<script>
  // 1. IMPORTS - autres composants et modules
  import Branch from './Branch.svelte';

  // 2. PROPS - données venant du parent (on en parlera plus tard)
  let { name = 'Yggdrasil' } = $props();

  // 3. STATE - état interne
  let isGlowing = $state(false);

  // 4. DERIVED - valeurs dérivées
  let status = $derived(isGlowing ? 'Il brille !' : 'Calme');

  // 5. FUNCTIONS - logique
  function toggleGlow() {
    isGlowing = !isGlowing;
  }
</script>

<!-- 6. MARKUP - structure HTML -->
<div class="tree" class:glowing={isGlowing}>
  <h1>{name}</h1>
  <p>Statut : {status}</p>
  <Branch />
  <button onclick={toggleGlow}>Changer la lueur</button>
</div>

<!-- 7. STYLES - styles CSS -->
<style>
  .tree {
    padding: 2rem;
    background: #2d5016;
    border-radius: 8px;
  }

  .glowing {
    box-shadow: 0 0 20px gold;
  }
</style>

Tu découvriras en détail les runes que tu vois ici dans les prochains lieux : $props() reçoit les données du parent (Asgard, module 4), $state garde l'état, et $derived calcule une valeur à partir d'autres valeurs (Chambre des Runes, module 3).

Organisation de la section Script

Ordre recommandé dans la section <script> :

<script>
  // 1. Imports
  import { onMount } from 'svelte';
  import ChildComponent from './ChildComponent.svelte';

  // 2. Props ($props)
  let { title, count = 0 } = $props();

  // 3. État local ($state)
  let internalState = $state('initial');

  // 4. Valeurs dérivées ($derived)
  let doubled = $derived(count * 2);

  // 5. Fonctions
  function handleClick() {
    internalState = 'clicked';
  }

  // 6. Effets et cycle de vie ($effect, onMount)
  $effect(() => {
    console.log('Count a changé :', count);
  });

  onMount(() => {
    console.log('Composant monté');
  });
</script>

Cet ordre se lit comme une saga : d'abord qui arrive (imports et props), ensuite ce que le composant sait (état et valeurs dérivées), et enfin ce qu'il fait (fonctions et effets).

Dans le code plus ancien (Svelte 4), tu verras export let au lieu de $props(), et des étiquettes $: au lieu de $derived et $effect. Cette syntaxe est dépréciée : dans les composants qui utilisent les runes, c'est une erreur.

Importer des composants

<script>
  // Importer un composant depuis le même répertoire
  import Warrior from './Warrior.svelte';

  // Importer depuis un sous-répertoire
  import Shield from './equipment/Shield.svelte';

  // Importer depuis #lib (alias de src/lib dans SvelteKit 3)
  import Button from '#lib/components/Button.svelte';
</script>

<Warrior />
<Shield />
<Button>Clique-moi</Button>

Les composants sont les branches d'Yggdrasil : mieux ils sont organisés, plus puissant est l'arbre de l'application !

Code de cette leçon : App.svelte
<script>
  // Yggdrasil - Tree of Components
  import Warrior from './Warrior.svelte';
  import Ship from './Ship.svelte';

  let villageName = 'Svenheim';

  const warriors = [
    { id: 1, name: 'Ragnar', strength: 95, weapon: 'Axe' },
    { id: 2, name: 'Bjorn', strength: 88, weapon: 'Sword' },
    { id: 3, name: 'Ivar', strength: 70, weapon: 'Bow' }
  ];

  const ships = [
    { id: 1, name: 'Drakkar of the North', crew: 50 },
    { id: 2, name: 'Sea Wolf', crew: 35 }
  ];
</script>

<main class="village">
  <header>
    <h1>Village: {villageName}</h1>
    <p>Components like branches of Yggdrasil</p>
  </header>

  <section class="warriors">
    <h2>Warriors ({warriors.length})</h2>
    <div class="grid">
      {#each warriors as warrior (warrior.id)}
        <Warrior {...warrior} />
      {/each}
    </div>
  </section>

  <section class="ships">
    <h2>Fleet ({ships.length})</h2>
    <div class="grid">
      {#each ships as ship (ship.id)}
        <Ship {...ship} />
      {/each}
    </div>
  </section>
</main>

<style>
  .village {
    font-family: 'Georgia', serif;
    max-width: 800px;
    margin: 0 auto;
    padding: 2rem;
    background: #1a0f0a;
    color: #e8d5b7;
    min-height: 100vh;
  }

  header {
    text-align: center;
    border-bottom: 2px solid #d4af37;
    padding-bottom: 1rem;
    margin-bottom: 2rem;
  }

  h1 { color: #d4af37; }
  h2 { color: #d4af37; margin-bottom: 1rem; }

  section {
    margin-bottom: 2rem;
  }

  .grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
  }
</style>

Entrées de la documentation utilisées dans cette leçon

Tu as repéré une erreur dans cette leçon ?

Teste tes connaissances

Réponds aux questions de cette leçon. Choisis une réponse pour voir tout de suite si elle est correcte.

  1. 1. Dans quel ordre les sections d'un fichier de composant Svelte doivent-elles apparaître ?

Tâches pratiques dans le jeu

  • Tri vertical

    Ordonne les éléments de la section script dans l'ordre recommandé :

Articles utiles