Fermer

janvier 28, 2022

Ce que les frameworks Web résolvent et comment s'en passer (Partie 1)


Résumé rapide ↬

Dans cet article, Noam Rosenthal plonge dans quelques fonctionnalités techniques communes à tous les frameworks et explique comment certains des différents frameworks les implémentent et ce qu'ils coûtent.

Je suis récemment devenu très intéressé par la comparaison des frameworks avec le JavaScript vanille. Cela a commencé après une certaine frustration que j'ai ressentie en utilisant React dans certains de mes projets indépendants, et avec ma connaissance récente et plus intime des normes Web en tant qu'éditeur de spécifications. les frameworks ce que la plate-forme Web a à offrir comme alternative allégée, et si c'est suffisant. Mon objectif n'est pas de dénigrer les frameworks, mais plutôt de comprendre les coûts et les bénéfices, de déterminer si une alternative existe, et de voir si nous pouvons en tirer des enseignements, même si nous décidons d'utiliser un framework.

Dans ce premier cas. partie, je vais approfondir quelques caractéristiques techniques communes à tous les frameworks, et comment certains des différents frameworks les implémentent. J'examinerai également le coût d'utilisation de ces frameworks.

Les Frameworks

J'ai choisi quatre frameworks à examiner : React, qui est le plus dominant aujourd'hui, et trois nouveaux concurrents qui prétendent faire les choses différemment de React.[19659007]React
"React facilite la création d'interfaces utilisateur interactives. Les vues déclaratives rendent votre code plus prévisible et plus facile à déboguer. ]« Svelte est une nouvelle approche radicale de la création d'interfaces utilisateur… une étape de compilation qui se produit lorsque vous créez votre application. Au lieu d'utiliser des techniques telles que la différenciation virtuelle du DOM, Svelte écrit du code qui met à jour chirurgicalement le DOM lorsque l'état de votre application change. modèles, et une poignée de fonctionnalités bien pensées. »

Pour résumer ce que les frameworks disent de leurs différenciateurs :

  • React facilite la création d'interfaces utilisateur avec des vues déclaratives.
  • SolidJS suit la philosophie de React mais utilise une technique différente.
  • ]Svelte utilise une approche au moment de la compilation des interfaces utilisateur.
  • Lit utilise les normes existantes, avec quelques fonctionnalités légères supplémentaires.

Ce que les frameworks résolvent

Les frameworks eux-mêmes mentionnent les mots déclaratif, réactivité et DOM virtuel. Plongeons-nous dans ce que cela signifie.

Programmation déclarative

La programmation déclarative est un paradigme dans lequel la logique est définie sans spécifier le flux de contrôle. Nous décrivons ce que le résultat doit être, plutôt que les étapes qui nous y mèneraient.

Au début des frameworks déclaratifs, vers 2010, les API DOM étaient beaucoup plus simples et détaillées, et l'écriture d'applications Web avec JavaScript impératif était nécessaire. beaucoup de code passe-partout. C'est alors que le concept de "modèle-vue-vue-modèle" (MVVM) est devenu répandu, avec les frameworks Knockout et AngularJS alors révolutionnaires, fournissant une couche déclarative JavaScript qui gérait cette complexité à l'intérieur de la bibliothèque.

MVVM n'est pas un terme largement utilisé aujourd'hui, et c'est en quelque sorte une variation de l'ancien terme "liaison de données". interface utilisateur.

Tous les frameworks d'interface utilisateur populaires fournissent une certaine forme de liaison de données, et leurs didacticiels commencent par un exemple de liaison de données.

Voici la liaison de données dans JSX (SolidJS et React) :

 fonction BonjourMonde() {
 nom const = "Solide ou Réagir" ;

 retourner (
     
Bonjour {nom} !
) }

Liaison de données dans Lit :

 la classe HelloWorld étend LitElement {
 @propriété()
 nom = 'allumé';

 rendu() {
   return html`

Bonjour ${this.name}!

`; } }

Liaison de données dans Svelte :

 

Bonjour {name} !

La réactivité

La réactivité est un moyen déclaratif d'exprimer la propagation du changement.

Lorsque nous avons un moyen d'exprimer de manière déclarative la liaison de données, nous avons besoin d'un moyen efficace pour le framework pour propager les modifications.

Le moteur React compare le résultat du rendu avec le résultat précédent, et il applique la différence au DOM lui-même. Cette façon de gérer la propagation des modifications s'appelle le DOM virtuel.

Dans SolidJS, cela se fait de manière plus explicite, avec son magasin et ses éléments intégrés. Par exemple, l'élément Show garderait une trace de ce qui a changé en interne, au lieu du DOM virtuel.

Dans Svelte, le code "réactif" est généré. Svelte sait quels événements peuvent provoquer un changement et génère un code simple qui trace la ligne entre l'événement et le changement DOM. éléments.

Plus après le saut ! Continuez à lire ci-dessous ↓

Logique

Lorsqu'un framework fournit une interface déclarative pour la liaison de données, avec sa mise en œuvre de la réactivité, il doit également fournir un moyen d'exprimer une partie de la logique qui est traditionnellement écrit impérativement. Les blocs de construction de base de la logique sont « si » et « pour », et tous les principaux frameworks fournissent une certaine expression de ces blocs de construction. une primitive "conditionnelle". Dans React, cela ressemble à ceci :

const [hasError, setHasError] = useState(false);
renvoie une erreur ?  : nul ;
…
setHasError(true);

SolidJS fournit un composant conditionnel intégré, Show :


  

Svelte fournit la directive #if :

{#if state.error}
  
{/si}

Dans Lit, vous utiliseriez une opération ternaire explicite dans la fonction render :

render() {
 retourner cette erreur ? html`` : nul ;
}

Listes

L'autre primitive commune du framework est la gestion des listes. Les listes sont un élément clé des interfaces utilisateur – liste de contacts, notifications, etc. – et pour fonctionner efficacement, elles doivent être réactives, et non mettre à jour toute la liste lorsqu'un élément de données change.

Dans React, la gestion des listes ressemble à ceci :

contacts.map((contact, index) =>
 
  • {Nom du contact}
  • )

    React utilise l'attribut spécial key pour différencier les éléments de la liste et s'assure que toute la liste n'est pas remplacée à chaque rendu.

    Dans SolidJS, le for[Lesélémentsintégrés et index sont utilisés :

    
      {contact => 
    {contact.name}
    }

    En interne, SolidJS utilise son propre magasin en conjonction avec for et index pour décider quels éléments mettre à jour lorsque les éléments changent. C'est plus explicite que React, ce qui nous permet d'éviter la complexité du DOM virtuel.

    Svelte utilise la directive eachqui est transpilée en fonction de ses mises à jour :

    {#each contacts as contact}
      
    {nom.contact}
    {/chaque}

    Lit fournit une fonction repeatqui fonctionne de manière similaire au mappage de liste basé sur key de React :

    repeat(contacts, contact => contact.id,
        (contact, index) => html`
    ${contact.name}
    `

    Modèle de composant

    Une chose qui sort du cadre de cet article est le modèle de composant dans les différents frameworks et la manière dont il peut être traité à l'aide d'éléments HTML personnalisés.

    Remarque : C'est un gros sujet, et j'espère le traiter dans un prochain article car celui-ci serait trop long. 🙂

    Le coût

    Les frameworks fournissent une liaison de données déclarative, des primitives de flux de contrôle (conditions et listes) et un mécanisme réactif pour propager les modifications.

    Ils fournissent également d'autres éléments importants, comme un moyen de réutiliser composants, mais c'est un sujet pour un article séparé.

    Les frameworks sont-ils utiles ? Oui. Ils nous offrent toutes ces fonctionnalités pratiques. Mais est-ce la bonne question à se poser ? L'utilisation d'un framework a un coût. Voyons quels sont ces coûts.

    Taille de l'ensemble

    Lorsque je regarde la taille de l'ensemble, j'aime regarder la taille réduite non Gzip. C'est la taille la plus pertinente pour le coût CPU de l'exécution de JavaScript.

    • ReactDOM est d'environ 120 Ko.
    • SolidJS est d'environ 18 Ko.
    • Lit est d'environ 16 Ko.
    • Svelte est d'environ 2 Ko. KB, mais la taille du code généré varie.

    Il semble que les frameworks d'aujourd'hui font un meilleur travail que React pour garder la taille du bundle petite. Le DOM virtuel nécessite beaucoup de JavaScript. Il est impossible de démarrer un projet frontal sans configurer Node.js et un bundler tel que Webpack, traitant de certains changements de configuration récents dans le pack de démarrage Babel-TypeScript, et tout ce jazz.

    Le plus expressif et le plus petit plus la taille du bundle du framework est importante, plus la charge des outils de construction et du temps de transpilation est importante. Je suis d'accord, mais peut-être que la "construction" (comme avec Svelte et SolidJS) et les moteurs de modèles personnalisés côté client (comme avec Lit) sont également de purs frais généraux, d'un autre type ?

    Débogage

    Avec la construction et la différents types de coûts.

    Le code que nous voyons lorsque nous utilisons ou déboguons l'application Web est totalement différent de ce que nous avons écrit. Nous nous appuyons désormais sur des outils de débogage spéciaux de qualité variable pour désosser ce qui se passe sur le site Web et le connecter avec des bogues dans notre propre code. Cela fonctionne très bien lorsqu'il n'y a pas de bugs. Mais essayez d'identifier la cause des rendus en boucle infinie et vous serez dans un monde de douleur.

    Dans Svelte, la taille du paquet de la bibliothèque elle-même est petite, mais vous allez expédier et déboguer tout un tas de code généré crypté qui est l'implémentation de la réactivité de Svelte, adaptée aux besoins de votre application.

    Avec Lit, il s'agit moins de construire, mais pour le déboguer efficacement, vous devez comprendre son moteur de modèle. C'est peut-être la principale raison pour laquelle mon sentiment envers les frameworks est sceptique.

    Lorsque vous recherchez des solutions déclaratives personnalisées, vous vous retrouvez avec un débogage impératif plus douloureux. Les exemples de ce document utilisent Typescript pour la spécification de l'API, mais le code lui-même ne nécessite pas de transpilation.

    Mises à niveau

    Dans ce document, j'ai examiné quatre frameworks, mais il y en a plus que je ne peux en compter ( AngularJS, Ember.js et Vue.js, pour n'en nommer que quelques). Pouvez-vous compter sur le framework, ses développeurs, sa vision et son écosystème pour travailler pour vous au fur et à mesure de son évolution ? Et une chose qui est plus frustrante que les bugs du framework, ce sont les bugs qui surviennent lorsque vous mettez à niveau un framework vers une nouvelle version sans modifier votre code.

    C'est vrai, ce problème existe aussi dans les navigateurs, mais quand il se produit, il arrive à tout le monde, et dans la plupart des cas, un correctif ou une solution de contournement publiée est imminente. De plus, la plupart des modèles de ce document sont basés sur des API de plate-forme Web matures ; il n'est pas toujours nécessaire d'aller à l'extrême.

    Résumé

    Nous avons approfondi un peu la compréhension des principaux problèmes que les frameworks tentent de résoudre et comment ils s'y prennent pour les résoudre, en nous concentrant sur la liaison de données, la réactivité, conditionnels et listes. Nous avons également examiné le coût.

    Dans la partie 2 (à venir la semaine prochaine !), nous verrons comment ces problèmes peuvent être résolus sans utiliser de cadre du tout, et ce que nous pouvons en apprendre . Restez à l'écoute !

    Remerciements particuliers aux personnes suivantes pour leurs révisions techniques : Yehonatan Daniv, Tom Bigelajzen, Benjamin Greenbaum, Nick Ribal et Louis Lazaris.