Accueil / Articles / HTMX contre la configuration par défaut des SPA : quand l’hypermédia bat un framework JavaScript

HTMX contre la configuration par défaut des SPA : quand l’hypermédia bat un framework JavaScript

Comment les attributs htmx remplacent le rendu côté client, ce que signifient réellement les tailles des bundles, ainsi qu’un guide équilibré indiquant où les applications hypermédias ont l’avantage et où React reste supérieur.

2260 mots

De nombreuses équipes choisissent React pour chaque nouveau projet, y compris les panneaux d’administration et les outils CRUD qui se résument principalement à des formulaires et des tableaux. htmx affirme qu’une grande partie de ces applications n’a jamais eu besoin d’un framework côté client : le serveur peut envoyer du HTML, et quelques attributs suffisent pour permettre à n’importe quel élément de récupérer et de remplacer des fragments de son contenu. Ce guide explique le fonctionnement d’htmx, compare son impact à celui de React, et met en évidence tant les véritables forces que les limites que ses partisans ont tendance à ignorer, afin que vous puissiez choisir une architecture en toute conscience plutôt que par habitude.

Il part du principe que vous avez déjà développé des applications web et que vous avez passé la majeure partie de votre temps avec React ou un framework similaire.

Comment les SPA sont devenus la norme pour tout

Autour de 2013, l’industrie a modifié son modèle de base. Au lieu que les serveurs renvoient des pages HTML, ils ont commencé à renvoyer du JSON, que le JavaScript dans le navigateur transforme ensuite en interface.

Pour certains produits, l’application à page unique a représenté un véritable progrès. Gmail, Figma et Google Maps stockent beaucoup d’informations dans le navigateur, et leurs interactions doivent sembler instantanées.

Le problème, c’est que ce modèle s’est étendu à tout. Un tableau de bord interne qui affiche des lignes et permet de les modifier a fini par adopter la même architecture qu’un outil de conception. Un site de marketing disposant d’un seul formulaire de contact a vu apparaître un outil de bundling, un routeur, une bibliothèque de gestion de l’état et une étape d’hydratation.

Cette approche par défaut entraîne des coûts concrets :

  • Deux bases de code, souvent dans deux langages différents
  • Un modèle de données défini des deux côtés
  • Une chaîne d’outils de compilation à maintenir et à mettre à jour
  • Un besoin permanent de maintenir l’état du client en synchronisation avec l’état du serveur
  • L’argument principal d’htmx est que de nombreuses applications supportent ces coûts sans obtenir en retour ce dont elles ont besoin.

    Qu’est-ce que htmx ?

    htmx est une petite bibliothèque JavaScript qui étend l’HTML avec des attributs. Grâce à eux, n’importe quel élément peut envoyer une requête HTTP et placer la réponse quelque part sur la page. C’est essentiellement tout ce que contient la bibliothèque.

    Une boîte de recherche en temps réel illustre bien cette idée. L’élément d’entrée indique quelle URL appeler, quel événement déclenche cette appel, et où le résultat doit être affiché :

    <input type="text"
           name="q"
           hx-get="/search"
           hx-trigger="keyup changed delay:300ms"
           hx-target="#results">
    
    <div id="results"></div>
    

    Lisez les attributs comme une phrase : lorsque la touche est relâchée et que la valeur a réellement changé, attendez 300 ms, envoyez une requête GET vers /search, et placez ce qui est retourné à l’intérieur de #results. Le modificateur delay:300ms atténue les entrées rapides, de sorte qu’une frappe rapide ne génère pas de requête à chaque touche.

    Le serveur ne renvoie pas de JSON. Il renvoie un fragment HTML prêt à l’emploi :

    <ul>
      <li>First result</li>
      <li>Second result</li>
    </ul>
    

    htmx insère ce fragment dans l’élément cible. Il n’y a ni analyse de JSON, ni template côté client, et aucun état du client qui pourrait différer de celui du serveur.

    Les attributs que vous utiliserez le plus

    • hx-get, hx-post, hx-put, hx-delete permettent de choisir la méthode HTTP et l’URL.
  • hx-trigger définit l’événement qui déclenche la requête, tel que click, keyup, load, every 2s ou revealed (lorsque l’élément apparaît dans la vue).
  • hx-target sélectionne l’élément qui reçoit la réponse.
  • hx-swap contrôle la manière dont la réponse est insérée : innerHTML, outerHTML, beforeend ou delete.
  • hx-indicator fait référence à un élément affiché pendant que la requête est en cours d’exécution.
  • hx-confirm demande à l’utilisateur de confirmer avant d’envoyer.
  • Ces éléments s’assemblent bien. Le fragment suivant supprime une ligne de tableau : le bouton envoie une requête DELETE, cible le premier tr qui l’entoure, remplace toute cette ligne par la réponse (généralement vide) et demande d’abord une confirmation. Le modificateur swap:1s retarde ce remplacement d’une seconde, ce qui permet une transition CSS pour effacer progressivement la ligne et donner l’impression que l’action est réactive :

    <tr>
      <td>Widget</td>
      <td>
        <button hx-delete="/items/42"
                hx-target="closest tr"
                hx-swap="outerHTML swap:1s"
                hx-confirm="Delete this item?">
          Delete
        </button>
      </td>
    </tr>
    

    Remarquez ce qui fait défaut : pas de fichier JavaScript distinct, pas d’étape de compilation et pas d’état côté client. Le serveur reste responsable de la suppression de l’élément et de la décision quant à ce que deviendra la ligne.

    Deux architectures côte à côte

    La différence est plus claire en termes de flux que par comparaison des outils.

    • Modèle SPA : le serveur envoie du JSON, le code client le rend et gère l’état ; l’utilisateur intervient, le client met à jour son état, le rend à nouveau et envoie du JSON en retour.
    • Modèle hypermédia : le serveur envoie du HTML, le navigateur l’affiche ; l’utilisateur intervient, le serveur répond avec du HTML mis à jour, et le navigateur le remplace.

    Dans le modèle hypermédia, il n’y a qu’une seule source de vérité : le serveur. Cela élimine toute une catégorie d’erreurs où le client croit tenir des informations différentes de celles indiquées par la base de données, comme des caches obsolètes ou des mises à jour optimistes qui n’ont jamais été synchronisées.

    Carson Gross, créateur d’htmx, présente cela comme un retour à ce que REST était censé être. Le REST de Roy Fielding inclut la contrainte HATEOAS (Hypermedia As The Engine Of Application State) : le serveur envoie des représentations contenant les actions disponibles ensuite. Une API JSON typique ne le fait pas ; le client doit savoir à l’avance quels endpoints existent. HTML le fait nativement, car un lien représente une transition d’état et un formulaire est une action. Que cette approche vous paraisse perspicace ou purement académique est un bon indicateur de votre opinion globale sur htmx.

    Mesurer la taille du bundle, et ce que cela ne vous dit pas

    Les tailles indiquées varient, il est donc utile de mesurer. Au moment de la rédaction, la version minifiée d’htmx pesait environ :

    htmx.min.js:  51,238 bytes raw
                  16,576 bytes gzipped   (16.2 KB)
    

    Les versions finales de React 19.2.8, le paquet React ainsi que le client DOM, pesaient quant à elles :

    react.production.js:            4,446 bytes gzipped
    react-dom-client.production.js: 94,757 bytes gzipped
    combined:                       98,420 bytes gzipped   (96 KB)
    

    Cela représente une différence d’environ six fois, et cela ne concerne que l’exécution de React. Une vraie application React inclut un routeur, une bibliothèque de gestion d’état, une couche de récupération de données ainsi que ses propres composants, ce qui fait que les fichiers compilés atteignent souvent plusieurs centaines de kilooctets. En revanche, la taille indiquée pour htmx correspond aux dépendances côté client complètes. Les chiffres exacts changent à chaque nouvelle version, il convient donc de les mesurer à nouveau en fonction des versions que vous comptez réellement distribuer.

    Cependant, soyez prudent avec les conclusions. La taille du fichier affecte le chargement initial, mais pas la vitesse des interactions ultérieures. Avec une bonne connexion, l’écart de temps de chargement est faible, et lors des visites répétées, les deux fichiers proviennent du cache. L’argument de performance le plus convaincant est que htmx ne comporte pas de phase d’hydratation, période pendant laquelle une page React générée côté serveur semble prête mais ignore les clics tant que ses gestionnaires d’événements ne sont pas attachés.

    Où htmx est véritablement utile

    • Une seule langue et une seule base de code. Une équipe travaillant avec Go, Python, Ruby ou C# peut développer l’application dans son intégralité. La validation se trouve en un seul endroit et le modèle de données est défini une seule fois.
    • Aucune chaîne de construction. Une seule balise script suffit. Il n’y a pas de configuration de bundler, pas de node_modules côté frontend, et aucune mise à jour des dépendances frontales.
    • Localisation du comportement. La fonction d’un élément est indiquée directement sur l’élément lui-même. Au lieu de suivre un clic à travers plusieurs fichiers et une base de données, on lit simplement le markup. C’est l’un des arguments les plus forts, car il concerne la maintenabilité plutôt que la vitesse.
    • L’état en un seul endroit. Il n’y a pas de cache client à invalider, aucune donnée obsolète, et pas d’actualisation optimiste à annuler.
  • Les équipes qui passent à htmx des applications lourdes en CRUD rapportent souvent une réduction du code frontend de 40 à 60 pour cent. Ce chiffre circule largement sans source principale claire, il convient donc de le considérer comme anecdotique, mais la tendance est constante dans tous les rapports.
  • Le résultat est de l’HTML généré côté serveur, ce qui permet aux robots d’indexation de voir le contenu et aux technologies d’assistance d’obtenir un marquage sémantique réel, à condition que vous écriviez un bon marquage.
  • Où htmx manque de maturité

    Ces sont les points qui ne sont souvent pas mentionnés.

    Interaction riche et continue

    Les éditeurs de type glisser-déposer, les tableaux de bord et les graphiques interactifs permettant des actions comme le balayage ou le zoom exigent une interaction continue plutôt que des requêtes discrètes. Dans htmx, chaque interaction implique un aller-retour vers le serveur. Pour un éditeur de texte, ce n’est pas un compromis acceptable ; cela exclut donc htmx de cette application.

    Latence sur des réseaux médiocres

    Ses partisans soulignent que l’hébergement à proximité a considérablement réduit les temps d’aller-retour, ce qui est vrai. Néanmoins, un utilisateur disposant d’une connexion mobile faible en zone rurale peut devoir attendre quelques centaines de millisecondes pour une opération que React traiterait localement en quelques millisecondes à peine. Les applications htmx fonctionnent très bien sur de bons réseaux mais se révèlent nettement moins performantes sur des réseaux médiocres, ce qui est l’inverse de la manière dont cet argument est généralement présenté.

    Aucun avantage pour les appareils mobiles ou en mode hors ligne

    htmx n’est utilisable que sur le web. React Native permet à une équipe de partager des concepts ainsi qu’une quantité significative de code avec des applications natives, de sorte que si le développement d’applications mobiles natives fait partie des objectifs, cela peut l’emporter sur tous les autres facteurs. L’utilisation hors ligne est également impossible, car chaque interaction nécessite le serveur.

    État complexe du côté client

    Les assistants en plusieurs étapes avec des champs interdépendants, les formulaires disposant d’une validation en temps réel entre champs, ou encore les écrans où plusieurs composants doivent réagir à un même changement deviennent complexes à gérer. Les équipes ajoutent généralement Alpine.js ou hyperscript, et à ce stade elles assemblent plutôt un framework à partir de composants que d’utiliser un framework prêt à l’emploi.

    Écosystème restreint et pool de talents limité

    React dispose d’un composant mature pour presque tous les widgets. Avec htmx, vous pouvez soit créer votre propre sélectionneur de dates, soit intégrer un outil JavaScript indépendant et gérer vous-même les limites. La maîtrise de l’outil est également importante : au moment où cet article est écrit, les enquêtes indiquent que React est utilisé par plus de 40 % des développeurs, contre environ 7 % pour htmx, avec un rapport de téléchargements sur npm d’environ 560 à 1. Cela influence la vitesse à laquelle les nouveaux employés deviennent productifs et la facilité avec laquelle on trouve des solutions en cas de blocage.

    Lire attentivement les chiffres d’adoption

    La réalité est plus nuancée que ce que chacun des deux camps suggère.

    • L’utilisation de React ne diminue pas. Il reste dominant en termes absolus avec un écart très important.
  • La satisfaction vis-à-vis de React diminue. Les données des enquêtes montrent que son utilisation reste stable tandis que les réponses indiquant « je ne l’utiliserais pas à nouveau » augmentent. Les gens continuent d’utiliser React, mais avec moins de plaisir, ce qui constitue un signe réel sans pour autant équivaloir à un abandon.
  • La croissance d’htmx est relative. Il a dépassé les 40 000 étoiles sur GitHub, en a ajouté environ 16 800 en 2024, et a dominé la catégorie frontend du classement JavaScript Rising Stars. Il s’agit d’une croissance rapide partant d’une base restreinte.
  • En résumé : React n’est pas remplacé, mais sa position de choix incontesté s’affaiblit. Il convient de garder à l’esprit que la plupart des contenus comparant htmx et React en ligne sont rédigés pour attirer du trafic de recherche, et des chiffres tels que le pourcentage de réduction du code ou divers indicateurs de vitesse sont reproduits sans citation des sources. Considérez-les comme indicatifs et vérifiez toujours les sources actuelles avant de les citer.

    Choisir entre les deux

    Sélectionnez htmx lorsque :

    • L’application repose essentiellement sur des formulaires et des listes : panneaux d’administration, outils internes, applications CRUD, sites de contenu, tableaux de bord affichant des données plutôt que de les manipuler.
    • Les forces de votre équipe se situent au niveau du backend.
    • Vous souhaitez une seule base de code que n’importe quel membre de l’équipe pourra maintenir dans quelques années.

    Sélectionnez React lorsque :

    • Le navigateur gère réellement un état important, comme c’est le cas pour les éditeurs, les outils de conception, la collaboration en temps réel ou la manipulation intensive de données.
    • Vous avez besoin d’applications mobiles natives ou d’un fonctionnement hors ligne.
    • Vous dépendez d’un écosystème de composants mature.

    Il existe également une troisième option souvent négligée : les utiliser toutes les deux. htmx peut gérer les écrans CRUD tandis que React alimente les deux ou trois vues qui en ont réellement besoin. Rien ne force l’adoption d’une architecture unique pour tout le produit, et combiner htmx avec des parties React est plus simple que de mixer deux frameworks SPA. Si vous utilisez déjà htmx, le guide de mise à niveau vers htmx 4 décrit les changements apportés par la prochaine version majeure.

    Les React Server Components s’inspirent en partie de l’idée d’hypermédia en déplaçant le rendu sur le serveur. Cependant, ils nécessitent encore l’environnement de exécution complet de React ainsi qu’un serveur compatible Node, ce qui fait d’eux une option peu légère ; il s’agit plutôt de React qui bénéficie de certains avantages tout en conservant son poids.

    Points clés

    • htmx permet à n’importe quel élément d’envoyer une requête et de remplacer le contenu par de l’HTML généré sur serveur, ce qui maintient le serveur comme unique source de vérité et élimine la synchronisation de l’état côté client.
    • Son temps d’exécution représente environ un sixième de celui de React avant même l’ajout de tout code d’application React, mais l’avantage réel réside davantage dans l’évitement de l’hydratation que dans une réduction du temps de chargement.
    • Il se distingue pour les applications CRUD, les outils internes et les sites de contenu, mais rencontre des difficultés avec les interactions continues, les réseaux médiocres, l’utilisation sur mobile, le mode hors ligne et un état côté client complexe.
    • Mélanger les deux constitue une architecture légitime, et non un compromis.

    La question plus pertinente derrière ce débat est de savoir comment une architecture conçue pour Gmail est devenue la valeur par défaut pour un formulaire à six champs. Personne n’avait vraiment tort ; un outil est devenu la valeur par défaut, et les valeurs par défaut cessent d’être examinées. Quelle que soit votre choix, y compris React, faites en sorte que ce soit une décision réfléchie et non une décision héritée.

    Lectures complémentaires

  • Décompte à retard zéro dérive en React : de setTimeout à CSS pur — Comparez setTimeout, requestAnimationFrame et une technique CSS sans JavaScript pour les décomptes en React, y compris le truc du retard unique qui maintient les chiffres synchronisés.
  • Budgets de performances pour JavaScript : imposition des limites des bundles en CI — Découvrez pourquoi JavaScript coûte bien plus que son temps de téléchargement, comment définir un budget de performances réaliste, et comment faire en sorte que webpack échoue les builds qui le dépassent.
  • Une demande Todo, deux architectures : ce que htmx supprime d’un stack CRUD — Suivez une seule demande d’ajout d’élément à travers un SPA React et une page htmx pour voir quels niveaux disparaissent, ce que le serveur prend en charge, et où htmx cesse d’être adapté.