Accueil / Articles / Svelte 5 Runes et SolidJS Signals : mises à jour de l’interface sans re-rendering

Svelte 5 Runes et SolidJS Signals : mises à jour de l’interface sans re-rendering

Voyez comment Svelte 5 compile les runes et SolidJS relie les signaux pour mettre à jour le DOM directement, en quoi cela diffère de React et Angular, et quand un changement est justifié.

1774 mots

Tout développeur React doit un jour expliquer pourquoi un composant s’affiche quatre fois alors que rien d’visible ne change, et pourquoi la solution passe par memo, un tableau de dépendances et une fonction de rappel stable. Svelte et SolidJS partent d’une hypothèse différente : si le framework sait exactement quel élément d’état alimente quel élément du DOM, il peut mettre à jour ce seul nœud et éviter complètement de réexécuter les composants. Cet article explique comment chacun d’eux y parvient, à quoi ressemble le code en pratique, où leur modèle diffère de celui de React et Angular, ainsi que comment décider si l’un ou l’autre convient pour votre prochain projet.

Le DOM virtuel était un moyen, pas une fin

L’idée fondatrice de React lors de son lancement en 2013 était le DOM virtuel. On décrit l’interface utilisateur comme une fonction de l’état. Lorsque l’état change, React appelle à nouveau votre composant, crée un arbre frais en mémoire, le compare au précédent, et n’applique que les différences au DOM réel.

Cette conception rend les interfaces bien plus prévisibles que la manipulation manuelle du DOM, et elle reste un modèle solide. Cependant, cela a un coût : la fonction du composant s’exécute à nouveau que son output ait besoin de changer ou non, un nouvel arbre est alloué, et une étape de comparaison détermine ce qui a réellement changé, tout cela pour mettre à jour un seul <span> dans le pire des cas. Si vous souhaitez connaître en détail ce que compare le mécanisme de conciliation et pourquoi, l’article sur le fonctionnement de la comparaison du DOM virtuel aborde ces points.

Une grande partie de l’API de React depuis lors — memo, useMemo, useCallback ainsi que, plus récemment, le React Compiler — a pour but d’éviter les opérations que le modèle de rendu et de différenciation effectuerait normalement. Le compilateur automatise la mémorisation, permettant aux développeurs d’écrire moins de code manuellement, mais le modèle sous-jacent reste inchangé : les composants sont réexécutés, et l’optimisation consiste à les convaincre de ne pas le faire. L’article sur ce que le React Compiler optimise et ce qu’il vous laisse faire aborde ces limites.

Svelte et Solid posent une question plus simple : que se passerait-il si la dépendance entre chaque élément d’état et chaque nœud DOM était connue avec précision, de sorte que seul ce nœud soit modifié lorsque l’état change ?

Svelte : un compilateur qui écrit le code de mise à jour pour vous

Svelte est avant tout un compilateur. Vous créez des composants dans des fichiers .svelte, et au moment de la compilation, Svelte les transforme en JavaScript pur qui manipule directement le DOM. Il n’y a ni DOM virtuel ni comparaison en temps de exécution, et seul un petit noyau en temps de exécution est envoyé au navigateur.

Dès Svelte 5, la réactivité s’exprime à l’aide de runes, des primitives explicites reconnues par le compilateur. Le composant ci-dessous déclare un état ainsi qu’une valeur dérivée de celui-ci, puis affiche les deux dans un bouton :

<script>
  let count = $state(0);
  let doubled = $derived(count * 2);
</script>
<button onclick={() => count++}>
  {count} doubled is {doubled}
</button>

C’est l’ensemble du composant. Il n’y a ni fonction de mise à jour ni tableau de dépendances. Vous incrémentez count comme s’il s’agissait d’une variable ordinaire, et comme le compilateur a déjà analysé quels éléments du markup lisent count et doubled, il génère du code qui met à jour précisément ces nœuds de texte. $derived est recalculé uniquement lorsque quelque chose qu’il lit change. Notez que les gestionnaires d’événements dans Svelte 5 sont des attributs ordinaires tels que onclick, remplaçant l’ancienne syntaxe de directive on:click.

Pourquoi les équipes l’apprécient

  • Sans hooks, fonctions de mise à jour ou composants enveloppants, les composants Svelte sont généralement nettement plus courts que leurs équivalents React. Moins de code signifie généralement moins d’endroits où des erreurs peuvent survenir et des revues plus rapides.
  • Bundles de petite taille. Comme la majeure partie du travail s’effectue au moment de la compilation, le coût du framework dans le navigateur est faible. Pour les sites de contenu, les pages d’accueil et tout ce pour quoi la première charge est cruciale, c’est un véritable avantage commercial.
  • Blocs de construction web familiers. Le markup, les styles ciblés et les scripts se trouvent dans un seul fichier et s’affichent comme du HTML, CSS et JavaScript. Il n’y a pas de conventions spécifiques à JSX telles que className, ce qui rend les fichiers accessibles aux designers et aux réviseurs qui ne travaillent pas avec React.
  • Pour les applications complètes, SvelteKit ajoute le routage, l’affichage côté serveur et des points d’entrée API, jouant le rôle de Next.js pour React, tout en offrant une configuration plus légère.

    Il convient de connaître dès le début une précision importante : les runes sont des fonctionnalités de compilateur, donc elles ne fonctionnent que à l’intérieur de fichiers .svelte et dans des modules nommés avec l’extension .svelte.js ou .svelte.ts. Déplacer de la logique réactive dans un fichier utilitaire ordinaire .js ne fonctionnera pas sans cette nomenclature.

    SolidJS : JSX qui s’exécute une seule fois

    À première vue, Solid peut facilement être confondu avec React. Il utilise JSX, il compose de petites fonctions, et un compteur a presque l’air identique :

    function Counter() {
      const [count, setCount] = createSignal(0);
      return (
        <button onClick={() => setCount(count() + 1)}>
          Count: {count()}
        </button>
      );
    }
    

    La différence qui surprend les développeurs React est que Counter s’exécute exactement une fois. Solid repose sur une réactivité fine grâce aux signaux. createSignal renvoie un getter et un setter, et le getter, count(), est une appel de fonction plutôt qu’une valeur simple. Lorsque JSX lit count() à l’intérieur d’une expression, Solid enregistre que ce nœud de texte particulier dépend de ce signal. Appeler setCount plus tard met à jour ce nœud de texte et rien d’autre. La fonction de composant n’était qu’une étape de configuration qui relie les signaux aux nœuds DOM ; elle ne s’exécute plus jamais, il n’y a donc rien à rérender.

    C’est ce modèle qui permet à Solid d’atteindre ou de se rapprocher des meilleures performances dans les benchmarks des frameworks courants, souvent proches de celles du JavaScript vanilla écrit manuellement. Considérez les classements des benchmarks comme un instantané et évaluez vos propres charges de travail, mais l’avantage architectural est réel : les mises à jour coûtent approximativement en proportion de ce qui a changé, et non en fonction de la taille de l’arbre des composants.

    Pourquoi les équipes l’apprécient

    • Aucun modèle mental de re-rendering nécessaire. La question de React concernant le pourquoi d’un rendu n’existe pas. useMemo, useCallback et React.memo n’ont pas d’équivalent, car il n’y a rien à sauter.
  • Effets prévisibles. Un effet s’exécute lorsque le signal qu’il lit change, et non simplement parce qu’un composant se rérendu à nouveau et que l’array de dépendances le permet. Les closures obsolètes, un piège bien connu de React, disparaissent en grande partie car les valeurs sont toujours lues à jour via des getters.
  • Passage progressif vers React. JSX et la composition de composants se transposent presque directement, de sorte qu’une équipe React doit principalement oublier les aspects difficiles plutôt que d’apprendre tout à nouveau.
  • Les habitudes qu’il faut abandonner

    Le modèle à exécution unique entraîne des conséquences qui compliquent la tâche des nouveaux arrivants. La déconstruction des props en haut d’un composant lit leurs valeurs une seule fois, ce qui perturbe la réactivité ; c’est pourquoi les props sont généralement accédés via props.name. Les retours anticipés et les expressions conditionnelles dans le corps de la fonction ne sont évalués qu’une seule fois, d’où l’existence chez Solid de composants de flux de contrôle tels que Show et For. Une fois ces règles comprises, elles deviennent cohérentes, mais elles constituent la principale source d’erreurs pour les développeurs venus de React.

    Comparaison avec React et Angular

    La différence fondamentale est plutôt philosophique que syntaxique.

    React a révisé son modèle de base avec des fonctionnalités de « re-exécution et comparaison », et a passé des années à ajouter des outils pour réduire les coûts liés à ce modèle. C’est toujours un choix excellent : son écosystème est inégalé, le recrutement se fait facilement, et le React Compiler diminue réellement la nécessité d’une mémorisation manuelle. L’inconvénient est que vous travaillez dans un modèle conçu selon les contraintes de son époque.

    Angular est l’option d’entreprise dotée de toutes les fonctionnalités, avec une injection de dépendances, RxJS et des conventions strictes pour presque tout. Il gère très bien de très gros bases de code, mais les procédures et la courbe d’apprentissage sont réelles. Ses changements les plus importants récents, à savoir les signaux et la détection de modifications sans zone, le rapprochent d’une réactivité fine du type popularisé par Solid.

    Cette convergence est visible dans l’ensemble de l’industrie. Angular a adopté les signaux, React a introduit un compilateur en temps de compilation, des frameworks plus récents comme Qwik s’appuient sur une réactivité fine, et Vue, dont les refs réactifs étaient toujours proches des signaux, explore ses propres stratégies de compilation. Il serait exagéré de dire que Svelte et Solid ont inventé chacune de ces idées, mais ils ont démontré tôt et clairement que la compilation et les signaux pouvaient soutenir un framework entier.

    Pourquoi les développeurs continuent d’avancer dans cette direction

    Trois raisons peu glamour expliquent la majeure partie de cet intérêt :

    • Moins de concepts de framework à retenir. L’attention se porte sur le produit plutôt que sur les sématiques de mise à jour du framework. Mémoriser correctement un callback n’est certainement pas considéré comme une tâche significative.
  • Prestations par défaut. Dans React ou Angular, il faut travailler avec soin pour obtenir une application rapide. Avec Svelte ou Solid, ralentir une application exige généralement des efforts importants.
  • Respect de votre temps. Des APIs plus petites, moins de code générique et moins d’embûches. Les enquêtes auprès des développeurs placent régulièrement ces deux frameworks en tête des choix les plus satisfaisants et les plus intéressants, tandis que leur utilisation globale continue de croître à partir d’une base relativement petite.
  • Faut-il changer ?

    Pour un produit existant, il est presque certain que ce ne sera pas immédiatement possible. Lorsqu’une application importante fonctionne déjà avec React ou Angular et que l’équipe maîtrise bien cette technologie, la réécriture en est l’un des moyens les plus fiables d’entraver un projet. La taille de l’écosystème compte également : React dispose d’une bibliothèque pour presque tous les besoins, et bien que les écosystèmes Svelte et Solid soient dynamiques et en croissance, ils sont plus petits ; il convient donc de vérifier dès le début que les éléments dont on a besoin, tels que des bibliothèques de composants, des outils de formulaire et des intégrations d’authentification, existent et sont maintenus.

    Le calcul change pour de nouveaux projets. Un projet à partir de zéro, un widget exigeant des performances élevées ou une outil interne constituent des contextes à faible risque pour tenter cette approche :

    • choisissez Svelte si vous souhaitez une courbe d’apprentissage la plus simple possible et une expérience fonctionnelle dans l’ensemble
  • Choisissez Solid si votre équipe travaille en JSX et souhaite un rendu maximal avec un modèle mental inspiré de React
  • Réservez React ou Angular lorsque l’ampleur de l’écosystème, la facilité de recrutement et les compétences existantes priment sur l’efficacité pure
  • Points clés

    • Le modèle de rendu et de comparaison de React est prévisible, mais le travail effectué est proportionnel à l’arbre des composants ; la mémorisation et le compilateur React réduisent cette charge sans modifier le modèle.
    • Svelte 5 intègre la réactivité dans le compilateur grâce à des éléments tels que $state et $derived, générant des mises à jour directes du DOM et offrant un exécutif léger.
    • Solid exécute chaque composant une seule fois et lie directement les signaux aux nœuds DOM, ce qui élimine les redessins mais exige de nouvelles habitudes en matière de props et de flux de contrôle.
    • L’écosystème dans son ensemble converge vers les mêmes idées : analyse en temps de compilation, utilisation de signaux plutôt que de re-rendering, et mises à jour directes au lieu de comparaisons diff.
    • Adoptez ces frameworks là où leurs forces sont pertinentes et où l’écosystème répond à vos besoins ; ne réécrivez pas une base de code fonctionnelle simplement pour suivre la tendance.