Svelte - Autoformation

Introduction

Lors du DevFest 2021, j’ai participé à un labs sur Svelte : Devenir Svelte avec Svelte.

J’ai trouvé le sujet intéressant donc :

Présentation

Svelte n’est pas à proprement parlé un framework mais plutôt un compilateur. Le principe “très général” est de créer des fichiers .svelte qui vont être “compilés” en fichier .js optimisé.

Un moyen de validé cela : le contenu du package.json. Svelte n’est pas une dépendant du projet mais un dépendance de développement. Donc svelte n’est pas inclus dans le livrable. Seul le code qu’il ajoute au code l’application avec comme objectif de faire les plus petits livrables possibles.

A noter que le framework a été crée par Rich Harris qui travaille au New York Times. Il trouvait que les outils actuels n’étaient pas assez performant donc il a crée le sien. Une conférence a voir : Rich Harris - Rethinking reactivity. Il est également le créateur de degit et rollup.

Introduction à Svelte

Le début

On commence par un petit retour sur Svelte car après tout, je n’ai fait du Svelte pendant 1 heure :).

Degit

Le projet commence (comme toujours …) par la génération d’un projet. Ici, on “copie” en utilisant degit qui est un clone plus rapide :

npx degit sveltejs/template github-repository-searcher
cd github-repository-searcher
npm install
npm run dev

Et c’est vrai que c’est rapide

Mise à jour du composant

  • export: permet de dire qu’une variable comme une propriété. Equivalent d’un @Input … un peu bizarre comme nom,
  • Le mapping des variables est similaire à Angular/Vue (et donc différent de React)
    <input type="text" name="test" placeholder="test" bind:value={testInputField}>
  • Gestion du formulaire : <form on:submit|preventDefault={onSubmit}>,
    • on:,
    • possibilité de mettre des actions comment preventDefault,
  • Réactivité : pour indiquer à Svelte qu’une variable doit être mise à jour en fonction d’éléments externes, il faut utiliser $:
    // La liste des repos va évoluer à chaque fois que repositories ou userSearchTerm va changer
    $: filteredRepos = repositories.filter((repo) => {
          return repo.name.toLowerCase().includes(userSearchTerm.toLowerCase());
      });

Petite note sur le sujet : la réactivité (semble-t-il) fonctionne sur le principe de détection d’un changement dans ce qui est utilisé. Par exemple ici, les variables repositories & userSearchTerm. Mais comment déclencher une action en cas de changement SANS utiliser la variable ? Pour remettre à zéro les termes de recherche quand les repos changent par exemple … Avec les informations récoltées à date, j’arrive à cela mais je doute que ce soit la solution :

export let repositories;

let userSearchTerm = "";
let previousSearchTerm = "";

$: {
    console.log('Someting changed ...')
    if(previousSearchTerm !== userSearchTerm) {
        console.log("userSearchTerm changed ?", userSearchTerm.length);
        previousSearchTerm = userSearchTerm;

    } else {
        console.log("repositories changed ?", repositories.length);
        userSearchTerm = "";
    }
}

Svelte Tutorial

On repart des bases

Après ce premier tout petit tuto, on repart de la documentation officielle.

Introduction

  • La compilation remonte des “conseils” ou des éléments à corriger (alt sur une balise img),
  • Les styles sont gérés au sein du composant (scope),
  • Pour intégrer de l’html : {@html},
    • Par contre, pas de nettoyage … il faut le faire soit même … dommage ?,

Reactivity

  • Gestion d’évènement on:<event>|<filter>,
  • $:,
  • $: : permet d’appeler une fonction pas uniquement une instruction,
  • Fonctionne uniquement sur assignation. La manipulation des tableaux nécessite donc une action supplémentaire,
  • Il faut bien assigner à l’objet pas à une référence dans un sous-objet de l’objet :
    • obj.subObj.property = 1 fonctionne,
    • const obj2 = obj.subObj; obj2.property = 1 ne fonctionne pas (enfin … si mais pas de réactivité),

Props

  • Encore une fois, le mot export …
  • Possibilité d’utiliser {…},
  • $$props : pour accéder à toutes les propriétés (à utiliser avec précaution),

Logic

  • Une nouvelle syntaxe {#if} ... {:else} ... {/if},
  • Idem pour le for {#each beers as beer} /* ... */ {/each },
  • Pour éviter les soucis dans la gestion des éléments du DOM, il faut référencer une référence dans la boucle : {#each beers as beer (beer.id)} /* ... */ {/each }. Sinon, il y a risque de confusion dans la gestion entre le tableau et les noeuds,
  • Gestion des promesses directement dans le template : {#await promise } ... {:then } ... {:catch} ... {/await},

Events

  • Syntaxe on:<event>|<modifier>={<function>},

Voilà une phrase qui montre la différence avec les autres frameworks :

In some frameworks you may see recommendations to avoid inline event handlers for performance reasons, particularly inside loops. That advice doesn't apply to Svelte — the compiler will always do the right thing, whichever form you choose.
  • Un modifier peut altérer le résultat d’un event comme preventDefault,
  • import { createEventDispatcher } from 'svelte' pour récupérer puis créer de quoi envoyer un évènement depuis un composant,
  • Les évènements ne remontent pas tout seul : gestion manuelle ou par forwarding.

Bindings

  • Permet de lier input à des variables,
  • Semble fonctionner à la mode Angular bind:value={b},
    • Gère les conversions vers numérique,
  • En fonction de éléments : bind:checked={yes},
  • Possibiliter de récupérer une référence vers l’élément : bind:this={var},

Lifecyle

  • onMount: Appelé après le premier rendu du composant,
    • Conseil : mettre le fetch dans cette méthode,
    • Non appelé en SSR,
    • Le callback retourné est appelé pendant le destroy,
  • onDestroy: le nom à le mérite d’être clair,
  • beforeUpdate: appelé juste avant une mise jour,
  • afterUpdate: pareil mais après,
  • tick: permet d’attendre le prochain rendu pour que certaines modifications soient prises en compte.

Store

Si j’ai bien compris, le nom est assez clair … Permet de conserver des données entre les différents composants de l’application.

Différents types :

  • writable : peut-être modifié,
    • Il est possible de binder en utilisant $ : <input bind:value={$name}>,
    • Il est possible d’affecter directement $name += '!' <=> name.set($name + '!'),
  • readable : uniquement en lecture,
  • derived : calculé depuis d’autres store,
  • Il est possible de créer son propre objet du moment que l’objet retourne subscribe,

Transitions

Permet de piloter des effets pour rendre l’interface plus zolie et agréable.

  • transition : permet de gérer un effet dans le deux sens sachant l’un sera l’inverse de l’autre,
  • in / out : permet justement de spécifier des effets différents,
  • des évènements existent pour suivre l’évolution des transitions : introstart, introend, outrostart, outroend,
  • Ajouter local permet de limiter à une modification de l’élément et pas à une modification de son parent,
  • {key <value>} ... {/key} permet de faire jouer des transitions si une valeur spécifique change,

Actions

Les actions sont du code supplémentaire qu’il est possible d’ajouter un composant. La fonction exposée- permet de recevoir le component et donc d’y associer des évènements, etc…
La fonction de retour permet de supprimer ce qui aurait été ajouté.

Classes (CSS)

Pour aider à la gestion des class sur un élément class="{current === 'foo' ? 'selected' : ''}" peut devenir class:selected="{current === 'foo'}".

Cette notation peut-être raccourci : class:big={big} devient class:big.

Component Composition

Pour qu’un composant doit pouvoir avoir des enfants, il faut lui ajouter dans son contenur : <slot></slot>. Pour améliorer les choses, il est possible de nommer <slot name='name' ></slot>.

Une variable spéciale permet de controler le rendu : $$slot.

Context

Fonctionnalité semble-t-il du même nom que celle présente dans React. Elle permet de passer des informations dans un arbre de composants sans passer les paramètres un par un.

La différene avec store :

  • Store : données accessibles dans toute l’application,
  • Context : données accessibles au niveau du composant et de ces descendants.

Elements spécial

  • <svelte:self> : pour qu’un composant puisse d’auto utiliser,
  • <svelte:component>: pour définir un composant dynamiquement en évitant les ifs,
  • <svelte:window> : pour accéder la fenêtre et capturer des évènements ou se lier à certaines propriétés,
  • <svelte:body>: idem mais pour body,
  • <svelte:head> : Permet d’insérer des éléments ou de changer le titre,
  • <svelte:fragment> : permet d’insérer des éléments sans casser le flux html (ng-template ?).

Module context

Il est possible de partagé du code entre plusieurs instances d’un composant utilisée dans une application :

<script context="module">
    let current;
</script>

Build a simple web app

Présentation

Je continue avec : Building a simple web app.

Prise de notes

Pas grand choses à dire … Ca utilise les choses vues dans le tutorial : c’est déjà cela.

Quelques petits changements :

  • Le bouton utilise un slot pour le text,
  • La valeur tweet est calculée sans le bouton mais par un $:,
  • Un textarea pour mieux voir le résultat,

MDN Svelte

Présentation

Il semble la MDN propose ses propres articles : let’s go !

Bim : le truc qui fait mal. Le premier article indique que le tuto de Svelte doit prendre 30 min … euh … je sais pas combien de temps, j’y ai passé mais pas 30 min …

Prises de note

Les premiers pas sont l’application de choses déjà vues. Le point important est d’essayer de se souvenir de nombreux “petits” trucs :

  • $: : je pense qu’on l’utilise souvent;
  • Le fait que Svelte détecte les changements lors des assignations donc todos.pushn’est pas détecté,
  • De la même manière, il faut être explicite sur les variables qui entraînent une action,
    • Cela fait un peu penser aux paramètres passés à React.useEffect(),
  • L’astuce “visibility:hidden” pour l’accessibilité,
  • bind:this={nameEl},
  • L’exemple sur le tick me paraît bien plus compréhensible,
  • Dans le même sens, l’exemple sur action est également très parlant.

Deux liens supplémentaires : ici et .

Conclusion

J’ai parcouru d’autres blog, sites, etc … C’était long mais c’était bon. J’aime bien les principes, à voir si cela peut-être utilisé dans un cas concret.