Pourquoi tous les frameworks front-end adoptent les Signals

JavaScriptSignalsRéactivitéFrontend
Pourquoi tous les frameworks front-end adoptent les Signals

Il y a quelque temps, je suis tombé sur un tweet d'Evan You, le créateur de Vue, qui expliquait le lien entre les Signals et les refs de Vue. Signals ? Aucune idée de ce que c'était. Et honnêtement, ça ne m'a pas plus intrigué que ça car Vue gérait déjà très bien la réactivité avec ref et computed, pourquoi aller chercher ailleurs ?

Sauf que ce mot revenait de plus en plus souvent. Angular annonçait l'arrivée des Signals. Svelte les intégrait avec ses Runes. Preact, Qwik, Solid... tout le monde semblait converger vers le même concept. J'ai fini par creuser. Et là, surprise : les Signals ne sont pas juste une tendance passagère. Ils sont en train de devenir le modèle de réactivité, au point qu'une proposition vise à les intégrer directement dans le langage JavaScript.

Qu'est-ce qu'un Signal ?

Un Signal est une primitive réactive qui encapsule une valeur et permet de réagir automatiquement à ses changements. Contrairement au modèle traditionnel de re-rendu complet des composants, les Signals permettent une réactivité fine-grained : seules les parties de l'interface qui dépendent réellement d'une valeur sont mises à jour.

// Exemple avec SolidJS
import { createSignal } from "solid-js"

const [count, setCount] = createSignal(0)

// Le signal track automatiquement ses dépendances
console.log(count()) // 0
setCount(5)
console.log(count()) // 5

L'élégance du modèle réside dans sa simplicité : trois primitives suffisent à couvrir la majorité des cas d'usage: Signal, Computed et Effect. Le tracking des dépendances est automatique, sans nécessiter de tableaux de dépendances comme avec les hooks React.

Le problème que les Signals résolvent

Les frameworks traditionnels comme React reposent sur un modèle de Virtual DOM et de re-rendu au niveau composant. Quand un état change, le composant entier se re-rend, puis une comparaison (diffing) détermine les modifications à appliquer au DOM réel.

Ce modèle a ses limites :

  • Les développeurs doivent explicitement optimiser avec useMemo, useCallback et React.memo
  • Les tableaux de dépendances des hooks sont source d'erreurs fréquentes
  • Le re-rendu de composants entiers peut entraîner des calculs inutiles

Les Signals inversent cette logique. Au lieu de re-rendre un composant et calculer ce qui a changé, ils savent exactement quelles parties de l'UI dépendent de quelle donnée. Quand une valeur change, seuls les nœuds DOM concernés sont mis à jour directement.

L'adoption massive par les frameworks

SolidJS : le pionnier moderne

SolidJS, créé par Ryan Carniato, a popularisé l'utilisation des Signals dans les frameworks modernes. Son approche compile le JSX en opérations DOM optimisées, combinant réactivité fine-grained et excellent DX.

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

Angular : la renaissance

Angular a introduit les Signals dans sa version 17, marquant un tournant majeur pour le framework. Cette adoption simplifie la gestion d'état et améliore significativement les performances en réduisant les calculs inutiles.

import { signal, computed } from '@angular/core'

const count = signal(0)
const doubled = computed(() => count() * 2)

Vue : l'évolution naturelle

Vue utilise un système réactif basé sur des proxies depuis sa version 3 avec la Composition API. Bien que l'API diffère légèrement, le concept sous-jacent est similaire aux Signals.

<script setup>
const count = ref(0)
const doubled = computed(() => count.value * 2)
</script>

Vue travaille actuellement sur une refonte de son système de rendu utilisant les Signals pour réduire la taille des bundles et améliorer les performances.

Svelte : les Runes

Svelte 5 a introduit les Runes, sa propre implémentation des Signals avec une syntaxe distinctive utilisant le préfixe $.

<script>
  let count = $state(0)
  let doubled = $derived(count * 2)
</script>

Preact et Qwik

Preact a ajouté un package @preact/signals qui s'intègre parfaitement avec son écosystème léger. Qwik, de son côté, utilise les Signals comme fondation de son approche de resumability, permettant des temps de démarrage quasi-instantanés.

Vers une standardisation native : la proposition TC39

Face à cette convergence, une initiative ambitieuse a émergé : standardiser les Signals directement dans JavaScript. La proposition, actuellement au Stage 1 du processus TC39, rassemble les auteurs et mainteneurs d'Angular, Vue, Solid, Svelte, Preact, Qwik, Ember, MobX, RxJS et bien d'autres.

Les objectifs de la proposition

La proposition s'inspire de l'effort Promises/A+ qui avait précédé la standardisation des Promises en ES2015. Les objectifs principaux sont :

  • Permettre l'interopérabilité entre frameworks
  • Réduire la taille des bundles en évitant de shipper chaque implémentation
  • Améliorer les performances grâce à une implémentation native
  • Faciliter le debugging avec un support intégré dans les DevTools

L'API proposée

// Création d'un signal d'état
const counter = new Signal.State(0)

// Lecture de la valeur
console.log(counter.get()) // 0

// Modification
counter.set(5)

// Signal calculé
const isEven = new Signal.Computed(() => counter.get() % 2 === 0)

Un polyfill déjà disponible

Un polyfill conforme à la spécification est disponible pour expérimenter. Plusieurs auteurs de frameworks ont déjà commencé à tester l'intégration avec leurs systèmes.

Pourquoi cette convergence maintenant ?

Plusieurs facteurs expliquent cette adoption simultanée :

Performance web critique

Les Core Web Vitals sont devenus un facteur de ranking SEO, poussant les développeurs à optimiser chaque milliseconde. La réactivité fine-grained élimine le overhead du Virtual DOM et réduit le JavaScript exécuté.

Expérience développeur simplifiée

Les Signals offrent un modèle mental plus simple que les hooks avec leurs règles et dépendances explicites. Le code devient plus prévisible et moins sujet aux bugs subtils de timing.

Maturité des compilateurs

L'avènement de compilateurs sophistiqués (SolidJS, Svelte, React Compiler) permet d'optimiser le code à la compilation. Les Signals s'intègrent naturellement dans cette approche, chaque framework pouvant compiler vers des opérations DOM optimales.

Et React dans tout ça ?

React reste le framework le plus utilisé mais suit une voie différente avec le React Compiler (anciennement React Forget). Cette approche utilise l'analyse statique à la compilation pour optimiser automatiquement les composants, éliminant le besoin de useMemo et useCallback manuels.

Cependant, React pourrait utiliser les Signals sous le capot à l'avenir et après tout, le Virtual DOM a toujours été un détail d'implémentation. Dan Abramov lui-même a suggéré que React observe de près l'évolution des Signals.

Les bénéfices concrets

Bundles plus petits

Sans runtime de Virtual DOM à shipper, les applications utilisant des Signals compilés sont significativement plus légères. Svelte affiche environ 1.6 kB compressé contre 42 kB pour React.

Meilleures performances runtime

Les benchmarks montrent que SolidJS et Svelte surpassent régulièrement React et Vue dans les tests de performance DOM, grâce à l'élimination du diffing.

Code plus maintenable

L'absence de tableaux de dépendances et le tracking automatique réduisent une catégorie entière de bugs liés à la réactivité.

Conclusion

L'adoption des Signals par l'ensemble de l'écosystème JavaScript n'est pas un hasard : c'est la reconnaissance d'un modèle de réactivité plus efficace et plus élégant. La proposition de standardisation au TC39, soutenue par les principaux acteurs du domaine, pourrait transformer fondamentalement le développement frontend.

Si la proposition aboutit, nous verrons un écosystème où les bibliothèques réactives fonctionneront de manière interopérable, où les bundles seront plus légers, et où les DevTools offriront un support natif pour visualiser les graphes de dépendances réactives.

Pour les développeurs, le message est clair : les Signals sont l'avenir de la réactivité en JavaScript. Que vous utilisiez Angular, Vue, Svelte ou Solid, vous travaillez déjà avec ce paradigme et bientôt, il pourrait être intégré directement dans le langage.