ngParis #17

Meetup angular, organisé par le bon coin. J'avais un peu arreté d'aller aux meetups angular (trop peu de contenu), mais là le programme annonçait un REX sur comment mélanger React et Angular, du coup, j'étais curieux.

Le bon coin, derrière leurs airs de sites des années 80 mis en ligne dans un garage possède en fait de formidables bureaux en plein Paris. Le premier site date de 2006 et est Norvégien, puis la France a été la première filiale en 2007 avant que le système ne s'implante dans plus de 35 pays.

La technologie sous-jacente est un moteur custom codé en C nommé blocket et réutilisé par toutes les filliales (qui peuvent donc faire des mises à jour de leur moteur facilement) avec quelques petites différences culturelles pour chaque pays.

D'un seul dev au départ, ils sont maintenant 250 dans la boite avec un objectif à 350 pour la fin de l'année. Le bon coin, c'est des chiffres de consultations extraordinaires. 90 millions de pages vues par mois, essentiellement des résultats de recherche, donc sans possibilité de mise en cache.

Ils parviennent quand même à un startRender moyen de 0.7s. 6e site le plus visité de France, 700.000 nouvelles annonces chaque jour, 2 datacenters de 400 serveurs. En terme de charge, c'est du très lourd, leur conso normale correspondant aux pics de charge de ce qu'on connait habituellement.

Au dela du cœur de l'appli, il y a toutes les applications de gestion (modération, monitoring, etc) qui sont développés dans des tas de langages différents. Il y en a pour tous les gouts : PostgreSQL, Python, Ruby, Go, Shell, PHP, des apps natives, du big data, de l'hadoop, du capybara.

Ah, et la question qu'on se pose tous. Non, le compte @TopBonCoin n'est pas officiel, le bon coin ne faisant actuellement aucune publicité ou community management.

Bon, assez parlé de l'hôte, place aux talks.

React et Angular

Julien Bouquillon, alias @revolunet viens nous faire un retour d'expérience sur l'intégration de React dans Angular. Il a entendu beaucoup de bien de React et a voulu voir si ça se plugguait facilement.

Ça fait deux ans qu'il fait de l'Angular, sur du mobile et sur du desktop et le problème récurrent pour lui, ce sont les perfs. Essentiellement sur mobile d'ailleurs. Les problèmes de perf sont les mêmes sur les deux plateformes, mais les desktop étant plus puissants, il faut vraiment de grosses apps pour ressentir les ralentissement.

Vu que React mets en avant sa rapidité, il a décidé de troquer les directives d'Angular par des composants React pour voir la différence. Pour lui le reste d'Angular est très bon. On gagne en productivité et en réusabilité, le framework fournit plein de choses de base et tout ça se teste facilement. Globalement, super framework... sauf pour les perfs.

What's wrong with Angular ?

Parce que le gros problème d'Angular se trouve dans le data-binding, bête et méchant. C'est le coté magique qui nous attire au début dans le framework, mais c'est aussi le goulot de performances. Quand on inclue une variable dans un template pour qu'elle soit bindée, l'algo simpliste d'Angular va simplement ré-évaluer chaque variable à chaque événement de l'utilisateur. C'est à dire au clic, au scroll, au touch, au keypress. Voire même sur des events qui ne viennent pas du user, comme le retour d'une requete HTTP.

Et ce, même si les éléments en questions sont en dehors du viewport, ou qu'ils n'ont aucun rapport avec l'élément actuellement modifié. Bête et méchant on vous dit.

Bon, sur une appli desktop, on voit pas trop le problème, ça va super vite. Mais sur mobile, on peut commencer à percevoir la lenteur, voir à la subir. À chaque interaction, la totalité du DOM est réevalué, c'est pas rien. C'est vraiment du dirty checking.

Si on veut fournir un expérience smooth, il nous faut viser du 60 fps, ce qui corresponds à 16ms pour un refresh. 16ms pour un refresh de tout le DOM, c'est pas énorme.

Malheureusement, Angular ne nous donne pas beaucoup de points d'actions pour pouvoir influencer ou améliorer ce rendering, le processus fait plus ou moins partie intégrante du core du méchanisme.

La version 1.3 a fait de grosses améliorations à ce sujet, d'au moins 50% de gain. Elle introduit aussi le principe des bind-once, et des filters stateful, qui peuvent n'être executés qu'une seule fois pour chaque valeur passée. On peut aussi éviter de mettre des méthodes à évaluer dans les templates mais simplement des variables, utiliser la syntax track by des ng-repeat et toujours essayer de mettre ses event handler sur les éléments les plus hauts.

Malheureusement, il reste le cas des keypress. Si j'ai un input, la totalité de mon DOM est réévalué pour chaque touche que va taper mon utilisateur.

Et React ?

React de son coté fonctionne avec un système intermédiaire entre ses data et le DOM, il y intercale un concept qui lui est propre : le virtual DOM. Les modifications de data influent directement sur le vDOM (qui n'est pas rendu directement), et seulement le diff entre le DOM actuel et le vDOM sont reportés dans le DOM. Ça marche très bien, et du coup seul ce qui a changé est modifié.

React intègre aussi par défaut un système d'event delegation intelligent. Plutôt que d'ajouter des handler sur plusieurs éléments, il ajoute un handler général sur la page et renvoie l'event au bon élément cliqué. On arrete comme ça de dupliquer les handlers.

Et surtout, React est explicite. Plus de magie. Chaque composant possède sa méthode render qui va retourner du HTML. On peut comme ça tester unitairement le rendu, mais surtout chaque composant est isolé et ses données ne fuitent plus vers l'extérieur. Seul le contenu du composant est modifié, sans que cela n'induise un rechargement de la totalité du DOM de la page.

Sans compter que React s'intègre parfaitement dans l'écosystem npm et browserify.

Benchmarks

Il nous a fait une démo d'un même composant codé une fois en Angular et une fois en React pour voir la différence de perfs. C'était un tableau de 100 éléments et de 5-6 colonnes. En cochant la première colonne de chaque ligne, on pouvait "barrer" l'élément.

En React comme en Angular, le chargement initial du composant prends environ autant de temps. Pas de gain à attendre de ce coté là. Par contre, si on coche une ligne du tableau Angular, les 1000 éléments sont ré-évalués alors que si on coche celle de React, seule la ligne cliquée est modifiée.

Là où c'est pire, c'est qu'en ajoutant un champ d'input au dessus du tableau Angular, chaque keypress ré-évaluait la totalité du tableau. Et pire que tout, on a ajouté un bouton qui ne faisait rien (pas de ng-click, rien). Et bien cliquer dessus rechargeait encore tout le DOM Angular.

Je crois que toute la beauté de React peut se résumer dans la phrase suivante de Julien :

En React, un bouton qui ne fait rien, ne fait rien.

Bon, et mon React il va rentrer dans mon Angular ?

Oui. Il est tout à fait possible de mettre un composant React au beau milieu d'une appli Angular. Il va vivre sa vie en isolation, sans générer de reflow Angular, et sans se modifier quand Angular se modifie.

Par contre si on veut l'introduire dans notre cycle Angular normal, il faut le wrapper lui-même dans une directive. Par contre, à partir du code de la directive, on entre dans un mode explicit > implicit où on va définir des callbacks à notre composant qu'il sera chargé d'appeller quand il voudra communiquer son état vers l'extérieur, et on ajoutera aussi des méthodes au composant pour pouvoir lui passer de nouvelles data depuis Angular.

C'est un peu plus de plomberie, mais on est alors certain qu'il ne se mettra pas à jour sans raison, et il pourra agir en isolation complète.

Il existe un projet, ngReact qui défini justement ce type de directive, mais ils vont trop loin et ajoutent des watchers automatiques pour passer les infos d'Angular vers React et vice-versa, ce qui nous fait revenir au problème de dirty checking du départ.

Conclusion

React peut s'intégrer correctement dans Angular et vivre sa vie correctement en profitant de manière isolée de ses avantages. La plomberie reste un peu manuelle, mais permet une belle isolation. Néanmoins, la philosophie de l'un et de l'autre étant tellement différentes, je ne suis pas sur qu'on tire vraiment le meilleur des deux mondes.

KillrChat

Duy Hai Doan, tech évangéliste chez Datastax nous a parlé d'un pet project de chat à base d'Angular, Spring Boot et Cassandra. C'est cool, il est payé pour faire des meetups et présenter Cassandra, du coup avec trois technos cools comme ça il peut réutiliser le même talk :)

L'idée de faire une appli de chat vient de sa frustration de faire des ateliers pour faire découvrir Cassandra et que les élèves ne repartent qu'avec un énième "Hello World" qui ne sert pas à grand chose. Là, il a une vraie appli qui touche à toutes les couches.

Et surtout, elle peut profiter des possibilités de scaling de Cassandra. En gros, quand le nombre de user se mets à grossir, il suffit d'augmenter le nombre de nœuds sur lesquels les données sont stockées dans Cassandra. Cassandra s'occupe de répartir les nouvelles données uniformément sur chaque nœud de manière à ce qu'aucun ne soit particulièrement submergé. Pour plus d'infos sur le fonctionne de Cassandra, je vous invite à relire mon compte-rendu du meetup nodejs paris.

Le chat qu'il a développé communique avec le back-end Spring Boot en websocket, avec SockJS. Entre les deux, il suffit de mettre un broker qui sait scaler (RabbitMQ, ZeroMQ, Kafka) qui implémente un simple système de pub/sub et front et back peuvent communiquer sans soucis, même avec une forte charge.

Et Angular dans tout ça ?

Duy Hai vient surtout du monde Java, le front c'est pas forcément son domaine. Mais il a kiffé Angular, il s'y est bien retrouvé. Il a aussi apprécié le fait qu'il y ait des outils pour se plugguer facilement avec Bootstrap (car comme il le dit lui-même, si on lui laisse le design d'un site ça sera horrible, avec bootstrap au moins c'est pas trop moche).

Il a quand même très rapidement implémenté des tas de bonnes pratiques en Angular (je ne sais pas si ce sont des bonnes pratiques issues de Java ou non). Par exemple, toute sa logique est distribuéed dans des services stateless, ses controllers se chargeant simplement d'un rôle de passe-plat.

Par contre, comme beaucoup, il s'est fait avoir par les $resources. Déjà, selon qu'on utilise les ressources avec des méthodes d'instances ou des méthodes de classe, ce n'est pas la même type d'objet qui est retourné et le chaining des promises en devient d'autant plus complexe (sans parler des promises angular qui ont leurs propres quirks).

Ce qu'il regrette dans Angular c'est qu'il faille une bonne connaissance de Javascript pour comprendre réellement ce qu'il se passe sous le capot. Heureusement pour lui, il a découvert angular-from-scratch qui se propose de recoder les mécaniques principales d'Angular depuis rien pour bien assimiler petit à petit chacun des concepts.

Globalement une présentation assez chouette, un REX avec des technos sympas.

Typescript

Pour finir, Paul Souche, de Sfeir nous parle de Typescript.

Bon, je vais la faire assez vite pour le coup. Typescript est une surcouche à Javascript, un peu comme Coffeescript, qui compile en Javascript. Le truc qu'apporte Typescript, c'est un typage fort des variables.

On peut désormais définir le type de chacun de nos arguments de fonctions et définir des interfaces de classe. Et si jamais le compilateur s'aperçoit qu'on essaie de faire rentrer des ronds dans des carrés, il nous balance une exception et il compile pas.

On peut aussi définir "facilement" des variables privées et publiques et même génerer automatiquement des getters et des setters. Ouais, ouais, comme un vrai javaiste.

Bon, à part ça y a des linters et ça génère des sourcemaps.

J'ai vraiment beaucoup de mal à voir l'intéret du truc, mais j'imagine que ça va encore plus plaire aux javaistes qui se mettent au front.

Buffet

Et comme souvent, le buffet qui suit les talks est toujours l'occasion de discuter et de rencontrer des gens très intéressants. Hésitez pas à venir taper la discut' si vous êtes dans un meetup la prochaine fois.

Concaténation, Compression, Cache

Quand on cherche à optimiser les performances de son site web, il y a trois éléments essentiels à faire avant toute chose. Trois méthodes très simples à mettre en place et qui apportent un retour direct et flagrant sur la vitesse de chargement.

Ces trois méthodes sont la concaténation, la compression et le cache. J'ai déjà abordé celles-ci lors d'une présentation aux HumanTalks de Septembre 2014, mais nous allons les détailler dans la suite de cet article.

Concaténation

Le principe de la concaténation est de regrouper plusieurs fichiers de même type en un seul, afin de se retrouver avec moins de fichiers finaux à télécharger. Les fichiers qui profitent le plus de ce système sont les fichiers CSS et Javascript.

La nature même du téléchargement d'assets fait que notre navigateur doit payer certains coûts, en millisecondes, à chaque nouvel élément téléchargé. Ces coûts sont de diverses natures:

TCP Slow start

TCP, le protocole de connexion qu'utilise HTTP, possède un mécanisme de slow-start qui lui permet de calculer la vitesse optimale de transmission de l'information. Pour parvenir à ce résultat, il doit effectuer plusieurs aller-retours entre le client et le serveur, en envoyant de plus en plus en plus de données, pour calculer la vitesse maximale possible d'émission/réception.

Si on envoie une multitude de petits fichiers, la transmission n'a jamais le temps d'atteindre sa vitesse optimale et doit recommencer ses aller-retours pour le prochain fichier. En groupant les fichiers en un fichier de plus grande taille, le coût de calcul n'est payé qu'une seule fois et le reste du fichier peut se télécharger à la vitesse maximum.

À noter que maintenir les connexions à votre serveur en Keep-Alive permet de réutiliser une connexion d'un asset vers le suivant et donc de ne payer le coût de calcul qu'une fois. Malheureusement, activer le Keep-Alive sur un serveur Apache risque aussi de limiter le nombre de connexions parallèle que votre serveur peut maintenir.

SSL

De la même manière, si votre serveur utilise une connexion sécurisée, il y a un échange de clés entre le client et le serveur qui s'effectue pour vérifier que les deux sont bien qui ils annoncent être. Ici encore, le coût de cet échange est payé sur chaque asset téléchargé. Mettre les fichiers en commun permet donc de ne payer le coût de cet échange qu'une seule fois.

Connexions parallèles

Finalement, il y a une dernière limite, purement du coté du navigateur cette fois-ci : le nombre de connexions parallèles. La norme HTTP indique qu'un navigateur devrait ouvrir un maximum de 2 connexions parallèles vers un même serveur. Techniquement, les navigateurs récents ont augmenté cette limite à une valeur entre 8 et 12 car 2 était beaucoup trop restrictif.

Cela signifie c'est que si vous demandez à votre page web de télécharger 5 feuilles de style, 5 scripts et 10 images, le navigateur ne va lancer le téléchargement que des 12 premiers éléments. Il commencera le téléchargement du 13e uniquement une fois qu'un des 12 premiers sera arrivé, et ainsi de suite. Ici encore, la concaténation vous permet de laisser plus de canaux disponibles pour télécharger les autres assets de votre page.

Les fichiers CSS et Javascript se concatènent très bien. Il suffit simplement de créer un fichier final qui contient le contenu mis bout-à-bout de tous les fichiers initiaux. Votre processus de build devrait pouvoir s'en charger sans problème, mais un solution simple peut s'écrire en quelques lignes :

cat ./src/*.css > ./dist/styles.css
cat ./js/*.js > ./dist/scripts.js

À noter que la concaténation d'images (CSS Sprites) est aussi possible, mais nous ne l'aborderons pas dans cet article.

Compression

Maintenant que nous avons réduit le nombre de fichiers, notre deuxième tâche va être de rendre ces fichiers plus légers, afin qu'ils se téléchargent plus rapidement.

Pour cela, il existe une formule magique formidable nommée Gzip qui permet de réduire de 66% en moyenne le poids des assets textuels.

La bonne nouvelle c'est que la majorité des assets que nous utilisons dans la création d'un site web sont du texte. Les briques principales comme le HTML, le CSS et le Javascript bien sur, mais aussi les formats classiques de retour de votre API : XML et JSON. Et beaucoup d'autres formats qui ne sont en fait que du XML déguisé : flux RSS, webfonts, SVG.

Gzip, et c'est assez rare pour le souligner, est parfaitement interprété par tous les serveurs et tous les navigateurs du marché (jusque IE5.5, c'est dire). Il n'y a donc aucune raison de ne pas l'utiliser.

Si un navigateur supporte le Gzip, il enverra un header Accept-Encoding: gzip au serveur. Si le serveur décèle ce header dans la requête, il compressera le fichier à la volée avant de le retourner au client, en y ajoutant le header Content-Encoding: gzip, et le client le décompressera à la reception.

L'avantage est donc d'avoir un fichier de taille réduite qui transite sur le réseau, avec en contrepartie le serveur et le client qui s'occupent respectivement de la compression/décompression. Sur n'importe quelle machine issue des 10 dernières années, l'overhead de la compression/décompression en gzip est absolument négligeable. Par contre, le fait d'avoir un fichier bien plus léger qui transite sur le réseau permet des gains très importants.

Les librairies de compression Gzip sont disponibles sur tous les serveurs du marché, il suffit généralement simplement de les activer en leur indiquant les types de fichiers qui doivent être compressées. Vous trouverez ci-dessous quelques exemples sur les serveurs les plus connus :

Apache

<IfModule mod_deflate.c>
  <IfModule mod_filter.c>
    AddOutputFilterByType DEFLATE "application/javascript" "application/json" \
    "text/css" "text/html" "text/xml" [...]
  </IfModule>
</IfModule>

Lighttpd

server.modules += ( "mod_compress" )
compress.filetype  = ("application/javascript", "application/json", \
"text/css", "text/html", "text/xml", [...] )

Nginx

gzip on;
gzip_comp_level 6;
gzip_types application/javascript application/json text/css text/html text/xml
[...]; 

S'il y a bien une optimisation de performance qui nécessite peu de travail à mettre en place et qui améliore grandement les performances de chargement, c'est bien le Gzip. Cela ne nécessite aucun changement sur les fichiers servis, uniquement une activation de config sur le serveur.

Minification

Pour aller plus loin, vous pouvez aussi investir sur la minification de vos assets. HTML, CSS et Javascript sont encore une fois les meilleurs candidats pour la minification.

La minification est un procédé qui va ré-écrire le code de vos assets dans une version qui utilise moins de caractères, et qui donc pésera moins lourd sur le réseau. D'une manière générale cela va surtout supprimer les commentaires et les sauts de ligne, mais des minificateurs plus spécialisés pourront renommer les variables de vos Javascript en des valeurs plus courtes, regrouper vos sélecteurs CSS ou supprimer les attributs redondants de vos pages HTML.

L'ajout d'un processus de minification est plus complexe que l'activation du Gzip, et les gains sont aussi moins importants. C'est pourquoi nous vous conseillons de toujours commencer par la compression Gzip.

Cache

À présent que nous avons réussi à limiter le nombre de fichiers et à faire baisser leur poids, la prochaine étape est de les télécharger le moins souvent possible.

L'idée principale ici est qu'il est inutile de faire télécharger à votre visiteur un contenu qu'il a déjà téléchargé et possède donc en local sur son poste.

Nous allons commencer par expliquer comment fonctionne le cache HTTP car c'est un domaine qui est généralement mal compris des développeurs. Il y a en fait deux principes fondamentaux à comprendre dans le cache HTTP: la fraicheur, et la validation.

Fraicheur

On peut voir la fraicheur d'un asset comme une date limite de consommation. Lorsque l'on télécharge un élément depuis le serveur, celui-ci nous l'envoie accompagné d'un header indiquant jusqu'à quelle date cet élément est encore frais.

Si jamais le client à besoin à nouveau du même élément, il commence par vérifier la fraicheur de celui qu'il a en cache. S'il est encore frais, il ne fait pas de requête au serveur, et utilise directement celui qu'il a sur son disque. On ne peut pas faire plus rapide, car il n'y a alors absolument aucune connexion réseau impliquée.

Par contre, si jamais la date de fraicheur est dépassée, alors le navigateur va lancer une nouvelle requête au serveur pour récupérer la nouvelle version.

En HTTP 1.0, le serveur retourne un header Expires avec la date limite de fraicheur. Par exemple: Expires: Thu, 04 May 2014 20:00:00 GMT. Dans cet exemple, si jamais le navigateur demande à nouveau le même asset avant le 4 Mai 2014 à 20h, alors il le lira depuis son cache, sinon il interrogera le serveur.

Cette notation a un défaut majeur dans le fait que les dates sont fixées de manière absolue. Cela signifie que le cache de tous les clients perdra sa fraicheur en même temps. Et vous aurez donc potentiellement tous les clients qui feront une nouvelle requête vers votre serveur en même temps pour se mettre à jour, ce qui peut générer un très fort pic de charge à cet instant.

Pour limiter cela et donner plus de flexibilité dans la gestion de la fraicheur, en HTTP 1.1, un nouveau header à été introduit : Cache-Control. Celui-ci accepte plusieurs arguments qui permettent de gérer plus finement la manière de mettre en cache, et celui qui nous intéresse ici est max-age qui permet de définir une durée relative de fraicheur, en secondes.

Votre serveur peut donc répondre Cache-Control: max-age=3600 pour indiquer que l'asset est encore frais pendant 1h (3600 secondes). En faisant ainsi vous pouvez espacer les appels sur une plus longue période.

Validation

La deuxième composante du cache est la validation. Imaginons que notre asset ai terminé sa période de fraicheur, nous allons donc récupérer une nouvelle version de celui-ci sur le serveur. Mais il est possible que l'asset n'ait pas réellement changé sur le serveur depuis la dernière fois. Il serait alors inutile de retélécharger quelque chose que nous avons déjà dans notre cache.

Le principe de validation permet au serveur de gérer cela. Soit l'asset du client est identique à l'asset du serveur, dans ce cas le client peut garder sa version locale. Soit les deux sont différents et dans ce cas le client doit mettre à jour son cache avec la version distante.

Lorsque le client a récupéré l'asset pour la première fois, le serveur lui a répondu avec un header Last-Modified, par exemple Last-Modified: Mon, 04 May 2014 02:28:12 GMT. La prochaine fois que le client fera une requête pour récupérer cet asset, il renverra la date dans son header If-Modified-Since, par exemple If-Modified-Since: Mon, 04 May 2014 02:28:12 GMT.

Le serveur compare alors la date envoyée et celle qu'il possède de son coté. Si les deux correspondent, alors il renverra un 304 Not Modified pour indiquer au client que le contenu n'a pas changé. Celui-ci continuera alors d'utiliser sa version locale. Ainsi, on évite de transmettre du contenu inutile sur le réseau.

Par contre si le serveur voit que le fichier qu'il possède est plus récent que la date envoyée, il répondra avec un 200 OK et le nouveau contenu. Ainsi, le client utilise désormais la dernière version.

En faisant ainsi, on évite donc de télécharger un contenu qu'on possède déjà.

Dans les deux cas, le serveur renvoie de nouvelles informations de fraicheur.

Comme pour la fraicheur, il existe deux couples de headers pour communiquer des informations de validation au serveur. En plus de Last-Modified / If-Modified-Since qui utilisent une date de modification, il est possible d'utiliser des ETags.

Un ETag est un hash qui identifie de manière unique chaque fichier. Si le fichier change, alors son ETag change aussi. Par exemple, le serveur retourne au client lors du premier appel un header ETag: "3e86-410-3596fbbc", et lorsque le client fait à nouveau appel à la même ressource, il envoie un header If-None-Match : "3e86-410-3596fbbc". Le serveur va comparer les deux ETags et retourner un 304 Not Modified s'ils sont identiques ou un 200 OK avec le nouveau contenu s'ils sont différents.

Last-Modified et ETag possèdent des comportements très similaires, mais nous vous conseillons d'utiliser Last-Modified en priorité.

En effet, la spec HTTP indique que si un serveur retourne un Last-Modified et un ETag, alors le navigateur doit prendre en priorité le Last-Modified. De plus, la majorité des serveurs génèrent l'ETag à partir de l'inode du fichier, de manière à ce que celui-ci soit modifié au moindre changement.

Malheureusement, ceci pose des soucis pour peu que vous ayez des serveurs redondés derrière un load-balancer où chaque serveur possède son propre filesystem et donc ses propres inodes. Deux fichiers identiques, sur deux serveurs différents auront des inodes différents et par conséquent des ETag différents. Votre système de validation ne fonctionnera plus dès lors que votre client sera redirigé vers un autre frontal.

À noter que ce problème n'apparait pas sous nginx, qui ne prends pas en compte l'inode dans la génération de son ETag. Sous Apache, l'option FileEtag MTime Size permet de le désactiver, ainsi que etag.use-inode = "disable" sous lighttpd.

Récapitulatif

À la lumière de ces explications, nous pouvons donc retracer le parcours classique du téléchargement d'un asset mis en cache.

  • Le client effectue une première requête pour récupérer un asset. Il récupère son Cache-Control: max-age pour la fraicheur et son Last-Modified pour la validation.
  • S'il demande à nouveau le même asset alors que celui-ci est encore frais, il le prends directement depuis son disque local.
  • S'il le demande au dela de sa date de fraicheur, il fait un appel au serveur en envoyant son If-Modified-Since.
  • Si le fichier sur le serveur possède la même date de modification que celle envoyée, il retourne un 304 Not Modified.
  • Si le fichier sur le serveur a été modifié, il retourne un 200 OK avec le nouveau contenu.
  • Dans tous les cas, le serveur retourne un Cache-Control et un Last-Modified.

Invalidation du cache

Mais le cache est un animal capricieux, et nous savons tous que :

Il y a deux choses complexes en informatique : invalider le cache et nommer les choses.

Et effectivement, invalider le cache de nos clients quand nous avons besoin de faire une mise à jour est extrêmement difficile. C'est en fait tellement difficile que nous n'allons pas le faire du tout.

Comme le navigateur mets en cache chaque URL, si nous souhaitons modifier un contenu, il nous suffit de modifier son URL. Et les URL, c'est quelque chose que nous avons en quantité illimité. Il nous suffit de modifier le nom d'un fichier pour générer un nouvelle URL. On peut ajouter un numero de version, un timestamp ou un hash à notre nom de fichier original pour lui générer une nouvelle url.

Par exemple : style-c9b5fd6520f5ab77dd823b1b2c81ff9c461b1374.css au lieu de style.css.

En mettant un cache très long sur ces assets (1 an est le maximum officiel de la spec), c'est comme si on les gardait en cache indéfiniment. Il nous suffit juste de mettre un cache plus court sur le fichier qui les référence (généralement le fichier HTML).

Ainsi, si on pousse en production une modification sur une feuille de style ou dans un script, il nous suffit de modifier les références à ces fichiers dans nos sources HTML pour que les clients téléchargent les nouveaux contenus. Le cache sur les fichiers HTML est beaucoup plus court, de manière à ce que les changements introduits par notre mise en production soient rapidement répércutées sur nos clients.

Les anciens contenus seront encore en cache chez nos clients mais cela n'a pas d'importance, nous ne les requêterons plus jamais et les éléments non-utilisés du cache des clients se vident régulièrement.

La technique est en fait très proche des Etag vus précédement à la différence qu'ici nous sommes maitres de la génération du nom unique de fichier et du moment où nous souhaitons invalider le cache de nos clients.

Au final, nous utilisons un mélange de ces deux techniques pour gérer un cache optimal.

Les éléments dont l'URL est significative, comme les pages HTML ou les retours d'une API définiront une fraicheur faible (de quelques minutes à quelques heures, en fonction de la fréquence moyenne de mise à jour). Ceci permet de s'assurer que le client aura rapidement la nouvelle version quand celle-ci est déployée, tout en limitant la charge sur le serveur et la quantité d'information transitant sur le réseau.

Pour les éléments dont l'URL n'est pas significative, comme les feuilles de styles, les scripts, les polices de caractère ou les images, on utilisera une fraicheur maximum d'un an. Ceci permettra au client de garder indéfiniment la ressource dans son cache sans avoir besoin d'interroger à nouveau le serveur. On générera par contre une URL différente en fonction d'un hash du contenu à chaque fois que le contenu vient à changer. On prendra bien garde à modifier les références à ces fichiers dans les pages HTML.

Conclusion

Nous avons donc vu comment trois points très simples permettent de diminuer grandement le nombre de total de fichiers à télécharger, les rendre plus légers, et les télécharger moins souvent.

La concaténation automatique des fichiers doit être intégrée dans votre processus de build, afin de garder un environnement de développement clair. La compression en gzip ne nécessite que quelques modifications sur vos serveurs. La mise en place d'une stratégie de cache optimale par contre nécessite à la fois des modifications sur le processus de build et sur la configuration des serveurs.

Toutes ces modifications sont relativement peu couteuses à mettre en place et ne dépendent aucunement ni de la technologie utilisée pour le front-end, ni de celle utilisée pour le back-end. Elles peuvent être mise en place quelle que soit votre stack technique. Il n'y a donc plus aucune raison pour ne pas les déployer dès aujourd'hui.

ParisJS #42

Hier soir, meetup parisjs chez In'Tech Info, une école d'informatique du coté des Gobelins (dont les locaux semblent être un ancien parking réaménagé). Néanmoins, grande salle, plein de nouveaux venus, ça fait plaisir.

Commençons par le gros point noir du meetup. Celui-ci était censé commencer à 19h, mais c'est seulement à 19h45 que les organisateurs commencent à prendre la parole pour annoncer le programme. Et présenter parisjs, et montrer le nouveau site, et essayer de faire une démo d'édition de markdown en live, et faire son auto-promotion, et donner la parole à tous les sponsors pour qu'ils fasse de même, et du coup c'est super long.

C'est le même travers que le meetup nodejs paris et paris.rb. Ça ne commence jamais à l'heure, et même quand ça commence, on doit encore se taper les publicités avant le film, comme au cinéma. La prochaine fois, je viendrai en retard.

Bon, fini d'être aigri, il y avait une annonce intéressante quand même. NUMA vient d'ouvrir un espace de coworking de 150m², avec café à volonté, ouvert 24h/24, à destination des développeurs, et avec un device lab.

Dev Avengers

Mais les talks ont ensuite relevé le niveau. Christophe Porteneuve, la bible vivante du Javascript, qui appelle tout les auteurs des grands frameworks par leurs petits prénoms et qui réfléchit encore plus vite qu'il ne parle était le premier sur scène. 37 ans, toutes ses dents, 19 ans dans le web, ça envoie du lourd.

Il nous a présenté les outils de travail intra-browser qui permettent d'améliorer la productivité de son workflow de travail. Fini le Ctrl-S, Alt-tab, Ctrl-R pour voir les modifications qu'on vient de faire, on est en 2015 bourdel.

Petite explication de l'utilité des sourcemaps, qui permettent, en ajoutant des commentaires dans un fichier minifié de faire le mapping vers les fichiers sources. Chrome les comprends depuis déjà 4 ans, et nous indique donc les erreurs dans la console réellement là où elles ont lieu dans les fichiers sources. Et encore mieux, elles peuvent faire le lien entre un fichier final et n'importe quel type de fichier source, même des preprocesseurs comme Sass, Less ou Coffescript.

Tout le reste du talk donnait des exemples avec Chrome, car c'est le browser qui possède actuellement les meilleurs outils, même si Firefox et IE12 sont pas loin derrière.

On sait tous qu'on peut modifier le HTML et le CSS à la volée avec l'inspecteur Chrome, mais on peut aussi le faire avec du JS. Le soucis c'est que nos modifs restent en live dans la page chargée, mais que c'est un peu plus compliqué pour les récupérer dans un vrai fichier sur le disque.

Du coup, la solution c'est les workspaces de Chrome. On lui définit un dossier de notre disque dur qui contient nos sources, et une fois qu'on lui a donné l'autorisation, on peut manuellement lui indiquer les mappings entre notre filesystem et notre network. Du coup, en faisant ainsi et avec les sourcemaps, on peut modifier directement un fichier source Sass depuis Chrome.

Bon, sauf que dans ce cas là, on perds la preview instantanée de nos modifs dans le browser, parce que Chrome n'a aucune idée de comment parser du Sass. Mais c'est là que notre outil de build en mode watch peut venir nous aider. Grunt, Gulp et Brunch proposent tous un moyen d'écouter les modifications du filesystem pour lancer des taches en fonction des fichiers modifiés.

Il nous a ensuite parlé de fb-flo, un outil de Facebook qui permet de lier un fichier actuellement chargé par Chrome (CSS ou JS) à un buffer ouvert dans son IDE, et de reporter automatiquement les modifs de l'un vers l'autre, sans avoir besoin de recharger la page.

Dernier outil pour gagner du temps en test crossbrowser, c'est BrowserSync. On ouvre autant de pages qu'on le souhaite sur différents browsers, desktop et mobile, et toute modification sur l'un (scroll, typing dans un formulaire, etc) est répercutée instantanément dans les autres. L'avantage est que pour les clics, il rejoue le même selecteur unique sur chaque device plutot que de cliquer à des coordonnées précises.

Du coup, si on récapitule :

  • Sourcemaps pour avoir la liaison entre un fichier minifié et les sources des preprocesseurs
  • Workspaces pour faire le mapping entre un fichier du disque dur et un fichier chargé par Chrome (marche avec les sourcemaps). Je modifie dans Chrome, ça change sur mon disque.
  • fb-flo pour faire du livereload du browser dès qu'un fichier du disque change. Je modifie sur mon disque, ça recharge dans Chrome.
  • BrowserSync pour tester sur plusieurs devices/browsers en parallèle.

On a discuté ensuite autour d'une bière et d'une pizza où il m'a convaincu d'essayer Stylus. Syntaxe "clean", à la ruby, jade ou coffeescript. Je ne suis pas fan de cette épuration habituellement, mais j'avoue n'avoir jamais réellement essayé. Par contre le fait de pouvoir redéfinir les propriétés de base CSS (du genre, dès que je mets telle propriété avec telle valeur, alors ça mets automatiquement telle autre). Et aussi, les variables des mixins sont scopées, ce qui est le truc qui m'ennuie le plus avec Sass.

Dans le même genre, il m'a vendu brunch comme étant un grunt-like à base de convention over configuration (ce qui est tout le contraire de Grunt et de son configuration over configuration over configuration...). Du coup, faut vraiment que je teste.

Et il a même dit du bien de famous (un peu moins d'angular, forcément).

IONIC

Cédric Lombardot nous parle de Ionic Framework.

Alors, Ionic c'est un framework qui combine Angular et Cordova pour développer des applications hybrides.

Cédric commence par nous expliquer les avantages et inconvénients de faire de l'hybride. Le gros avantage de l'hybride c'est que c'est le même code pour toutes les plateformes, ce qui évite de devoir faire deux applications, pour Android et iPhone, qui coutent deux fois plus cher.

Par contre, mieux vaut éviter l'hybride si on a besoin de perfs au top, parce qu'une surcouche sera toujours plus lente que du natif. Ce qui inclue tous les super effets d'animation mouf-mouf. Si on a besoin de certaines API très liées au device, Cordova ne nous y donnera pas forcément accès. Et finalement, si on n'a besoin de développer que pour une unique plateforme, autant partir sur du natif.

Dans les deux cas, pour pouvoir passer son app sur iPhone, il faudra passer par les 15 jours de validation Apple. Il n'y a rien dans les CGU d'Apple qui bloque l'hybride plus que le natif.

Maintenant, parlons de ce qu'apporte Ionic. Déjà, il utilise Cordova, qui est le moteur open-source utilisé par Phonegap. Il gère aussi parfaitement les affichages d'élements dans une page, même quand on fait apparaitre/disparaitre le clavier (source de bugs divers).

Avec Ionic, on fait une application, pas un site web. On passe sur un paradigme où on réfléchit en terme de "vues" (écrans), et on doit alors penser à comment ceux-ci s'emboitent, quel est le comportement du bouton back, etc.

Ionic est fourni avec des directives (Angular oblige) pour la majorité des éléments de UI classiques d'une app : header, footer, listes avec pull-to-refresh, swipe sur item pour avoir un menu, drag'n'drop, popup de choix d'action, slideshow, etc

Ça s'installe classiquement à base de npm et génère un code boilerplate avec une petite appli pour comprendre comment les différents éléments interagissent. Si vous voulez vraiment aller vite, il existe même le Ionic Creator pour générer sa UI à base de drag'n'drop.

Ça pêche encore du coté Android quand le browser par défaut est le stockbrowser, qui a des perfs bien moins bonne que Chrome. Il y a des solutions en cours de développement pour contrer ça. Il n'est pas non plus compatible sous Windows Phone pour le moment.

Coté UI, Ionic vient avec son propre style. Il y a des essais pour reproduire un style natif Android ou iPhone, mais c'est pas encore au point et jQuery mobile est plus avancé de ce coté là apparemment. Par contre, on a quand même le droit à une classe CSS sur le root indiquant si on est sous Android ou sous IOS pour tweaker notre app en fonction.

VIRTJS

Maël Nison est venu nous parler un peu plus de Ionic, qu'il a utilisé sur un projet perso nommé Start9.

Maël avait déjà présenté un émulateur gameboy qu'il avait développé en javascript. Il a cette fois-ci poussé le concept un peu plus loin en proposant un site web en Ionic, accessible donc depuis n'importe quel browser, sur lequel on puisse uploader ses roms Gameboy et y jouer directement dans le navigateur. L'avantage est d'avoir un système crossplatform, on peut commencer sa partie sur son téléphone dans le métro et la continuer au même endroit sur son desktop plus tard.

Le gros avantage est que c'est un simple site web. Pas besoin d'installer quoique ce soit pour l'utilisateur, et pas besoin de passer par la validation appStore pour le créateur.

Coté techno, c'est du node en backend, avec du sequelize (ORM pour taper sur PostgreSQL et SQLite). Systemjs et Traceur pour ses modules ES6 transformés en ES5. Comme ça, le jour où ES6 est partout, on peut enlever la transformation. Et sinon, du Ionic pour le front.

Pour la suite ils envisagent de supporter de plus en plus de jeux, et de plus en plus de consoles. Ils passeront aussi à Angular 2 quand il sortira (pour rester sur une stack ES6). Leur retour sur Ionic c'est que c'est cool mais encore jeune, les issues sont fixées rapidement (si les mainteners sont pas en vacances...).

Conclusion

Une bonne soirée ParisJS, avec 3 talks très intéressant, une grande salle, de la pizza pour tout le monde et des discussions intéressantes autour d'une bière.

Sketchfab & 3DHubs

Sketchfab organisait à Numa un meetup, en partenariat avec 3DHubs. Je suis arrivé en retard (19h pour début à 18h), et du coup j'étais très mal placé (sur un fauteuil dos à la scène, derrière un pilier, au fond). Vu qu'il n'y avait pas de micro pour les questions de l'audience, je n'ai pu qu'entendre les réponses.

Ce que j'ai pu en retirer, une machine "perso" coute dans les 3000€ et la majorité des gens sur 3DHubs ne le font pas pour gagner de l'argent (s'ils peuvent se rembourser la machine c'est déjà bien), mais pour rencontrer d'autres makers.

Et... c'était fini !

Néanmoins, en discutant un petit peu autour des tables j'ai découvert un appareil (dont j'ai oublié le nom) qui est une sorte de camera 3D qu'on clipse sur un iPad et qui permet de faire des scans 3D en tournant quelques minutes autour d'un objet. Je l'ai vu à l'œuvre sur le scan de plusieurs participants pour avoir leur buste, et le résultat était pas dégueu du tout pour un si petit appareil.

Plusieurs musées Londoniens ont déjà scanné et ouvert au public certaines de leurs œuvres. En France, l'intérêt ne décolle pas vraiment, nos musées sont plus protecteurs. Par contre, les initiatives un peu pirates pour aller faire des tours dans les jardins municipaux et scanner les statues commencent à prendre vie.

Bon, au final par curiosité c'était intéressant, mais je suis arrivé trop tard pour en tirer trop de choses.

React JS France #1

Premier meetup React, organisé par Deezer et Altima, chez Deezer. Bon panel de speakers pour une première, avec Matthias Lebrun d'Altima, Yannick Croissant de Deezer et Christopher Chedeau de React (Facebook).

React, où comment simplifier la conception d'UI

On commence par Matthias qui nous fait une intro à React pour ceux qui ne connaissent pas. Ça tombait bien, je ne connaissais pas et ça m'a bien donné envie d'essayer.

Le principe de React est de simplifier la conception des UI, où tout est devenu trop compliqué au fil des années. On avait un simple serveur qui nous renvoyait du HTML au début, maintenant on a des SPA qui vont chercher seulement leurs données depuis le serveur et doivent mettre à jour leur markup en fonction.

Avec React, tout est un composant. Chaque composant possède sa propre méthode render qui doit retourner un markup HTML qui sera inséré dans le DOM. L'avantage d'avoir une simple méthode comme ça pour chaque composant c'est que c'est facile à tester unitairement. Les composants sont simples, petits, isolés, et les méthodes sont donc faciles à tester.

Le composant possède aussi un état, une liste de variables internes qu'il peut modifier en réponse à certaines actions de l'utilisateur ou recevoir depuis un parent. Ces variables sont privées, et lui permettent de choisir les modifications à appliquer au markup.

Le moteur de template de React utilise une syntaxe jsx, qui est croisement entre du XML et du Javascript, ce qui fait un peu peur au premier abord. Mais c'est juste du sucre syntaxique, React arrive avec son pre-processeur qui transforme ce jsx dans nos fichiers js en du vrai js. Le pre-processeur arrive avec quelques autres goodies d'ES6, et sans doute aussi dans le futur avec des annotations, du type checking, etc.

Du coup, on a un vrai moteur de template, qui est tout simplement du js. On peut y faire des conditions, des boucles, du map, reduce, bref tout ce qu'on veut faire en js sans devoir passer par une complexe syntaxe de template. Il est donc là inutile de réinventer de la logique dans un autre langage.

React continue sur sa lancée de simplification en faisant en sorte que tout soit explicite. Ici, pas d'API polymorphe à la jQuery où les getters et les setters se mélangent. On a même certaines fonctions qui sont déconseillées (comme ajouter directement un innerHTML), et qui possèdent donc des noms bien flagrants pour montrer qu'on fait quelque chose de mal quand on les utilise (dangerouslySetInnerHTML).

Pour revenir rapidement sur la méthode render, qui est le cœur de React, on a aussi autour la méthode shouldComponentUpdate, qu'on peut overrider pour indiquer au moteur que non, là, vraiment, c'est pas la peine de faire un nouveau rendering du component, je sais qu'il n'a pas bougé. Dans le même ordre d'idée, on a accès aux events willMount, didMount et willUnmount pour lancer du code custom à différents moment de la vie d'un composant.

React possède un très puissant algo de rendering, qui va checker le retour du render d'un composant et de tout ses sous-composants pour savoir s'il doit mettre à jour ou non son rendu. Il batche toutes les modifications ensemble jusqu'au prochain rendering du browser, et rajoute un petit algo de diff pour la route.

Autre parti-pris, qui va dans le sens de la simplification, il n'y a pas d'héritage dans React, il n'y a que de la composition à base de mixins. On défini des méthodes qu'on pourra implanter dans différents composants, quels qu'ils soient (comme réagir à un event de scroll ou de resize par exemple).

React s'abstrait du DOM officiel aussi en réimplementant pas mal de choses, mais en le faisant ainsi de manière cross-browser. Il réimplémente par exemple le principe d'event capture et event bubbling, tout seul. Il en profite pour rajouter une petit optim de perf dans l'histoire; plutot que de repasser une nouvelle instance de l'objet event à chaque intermédiaire, il recycle toujours la même liste de x objets qu'il passe à chacun des handlers.

Idem, il possède sa propre représentation du DOM pour savoir quand faire des updates, qu'il appelle le virtual DOM (et je crois qu'ils utilisent JSDOM, mais pas sur).

Globalement, j'ai été convaincu par React et j'ai bien envie d'essayer sur un prochain projet ou side-project. La simplicité avec laquelle on peut gérer notre affichage simplifie pas mal de chose. Le markup n'est plus du tout source de la donnée, il se concentre juste sur afficher les choses d'une manière ou d'un autre quand elles changent. Les algos de diff, super simples à coomprendre, permettent de s'assurer qu'on ne render par les choses pour rien, et les exposer sous forme de méthodes testables rends le truc encore plus attractif.

Je pense que ça s'incruste facilement dans un projet Backbone, mais que ça doit être la bonne galère de le passer dans de l'Angular.

Isomorphic JS

La seconde présentation, de Yannick Croissant, nous parlait de Javascript isomorphique, ou de comment générer la même application en front comme en back. Bon, j'avais déjà assisté à son atelier à ParisWeb sur le même sujet, du coup j'ai surtout écouté d'une oreille distraite et n'ai pas pris de notes.

Néanmoins, de mémoire il était question des problèmes que cause le fait de partir en mode SPA.

Déjà on duplique de la logique de code entre le back et le front, ce qui est particulièrement flagrant au niveau des validations de formulaires. On veut fournir une expérience riche, du coup on ne veut pas perdre du temps avec des appels serveurs pour vérifier la validité d'un champ de formulaire, et on veut les tester rapidement en local, en y déportant des règles métiers. Mais on ne peut pas non plus l'enlever du backend pour des raisons de sécurité. On se retrouve donc souvent à coder deux fois la même chose, des deux cotés. Au début de NodeJS on pensait que le fait d'avoir le même langage des deux cotés allait permettre d'éviter de coder deux fois les choses, mais le langage n'a pas grand chose à voir là dedans, la question est plus générique au niveau de l'archi.

Avoir une appli SPA pose aussi de gros problèmes en terme de référencement. Même si Google comprends le JS, ou même si on peut faire des hacks à base de phantomJS pour générer des pages statiques à servir aux robots crawleurs, ça reste des pansements sur des jambes de bois. Le modèle n'est pas adapté.

React permet de solutionner ce problème de manière assez élégante. Le serveur génère un HTML à servir au client, incluant du React, qu'il peut lui même instancier et modifier, comme s'il tournait dans un browser. C'est un état initial qui est servi au client. Puis toutes les mises à jours suivantes sont simplement de nouveaux retours de l'API qui vont déclencher des mises à jour de la vue dans le client. Si on reload complétement la page, la nouvelle page rendue par le serveur retournera un nouvel état de départ, mais encore une fois les nouvelles modifs se feront sous forme de diff. On a là une approche incrémentale, qui permet des affichage de page plus rapides.

On touche là au meilleur des deux mondes. Sur une url données, dans un contexte donné, notre serveur nous donnera un HTML parfaitement formé, parfaitement adapté pour le crawling, le SEO, l'accessibilité, etc. Si le navigateur est en mesure d'executer React, il peut mettre à jour la vue de manière incrémentale en redemandant les nouvelles infos au backend, qui peut se permettre de la lui retourner de manière simple sous forme de data.

React, CSS in JS

Le dernier talk était de Chistophe Chedeau, de chez Facebook (et sans doute connu de certains d'entre vous pour son boulot sur Curse Gaming). Il nous a présenté React depuis sa création jusqu'à ce qu'il est aujourd'hui.

L'idée principale derrière Reacte était de simplifier la codebase de Facebook. Des milliers d'ingénieurs qui bossent sur du front-end en même temps, avec des compétences en HTML/CSS très variées. Il n'y a pas vraiment de dev front chez Facebook, tous les devs travaillent sur toutes les parties, qu'elles soient back ou front. Du coup, ils ont souhaité abstraire au maximum certaines parties du markup pour limiter les erreurs, et simplifier le développement.

Un des problèmes majeur de CSS qui se fait ressentir sur une codebase comme celle-là, c'est que tout dans CSS est globales. On definit une classe, elle va s'appliquer partout dans le markup. Certes on peut préfixer un selecteur pour le rendre plus precis, mais on n'est jamais sur à 100% d'avoir une isolation parfaite. Un autre dev peux, consciemment ou non, overrider nos styles. En utilisant une méthode comme BEM, on peut limiter ce problème mais alors on rends le code extremement difficile à minifier, avec des classes à rallonge sur presque tous les éléments.

Le second problème majeur est qu'il est très difficile de supprimer du code. Il n'y a pas de couverture de code comme dans d'autres langages qui pourrait être déduite par des tests unitaires. Quand on supprime du CSS, on ne sait jamais réellement ce qu'on va casser.

Et pour finir, ils souhaitaient un moyen simple de pouvoir partager des constantes entre PHP, Javascript et CSS (un code couleur, un nombre d'éléments à afficher, un flag de feature flipping, etc).

Ils ont donc planché sur un moyen de créer des composants isolés, qui chargent leurs propres dépendances, qui ne se fassent pas overrider par l'extérieur et qui ne puissent pas non plus le faire.

Leur action principale, pour obtenir ce pouvoir, a été de convertir le CSS en Javascript. Tout simplement en React, ils n'écrivent pas leurs propriétés de style dans du CSS mais dans des objets JSON (légérement améliorés avec quelques helpers). Cette partie m'a un peu fait peur, et a continué à me suprendre dans le reste de la présentation. Finalement, après en avoir discuté avec d'autres devs qui font déjà du React régulièrement, cette approche n'est pas obligatoire et est même rarement employée : on continue d'utiliser des classes pour le style.

Bref, ces propriétés JSON/CSS sont ensuite appliquées directement en style= sur les éléments du markup. L'avantage de cette méthode barbare est qu'on est certain qu'on ne pourra pas se faire overrider par d'autres classes (style a la prio la plus forte), et comme on ne déclare pas de classe, on ne va rien overrider à l'extérieur non plus. C'est assez malin.

De plus, ils en profitent pour "optimiser" certaines règles au passage (si on ne mets pas d'unité, c'est des px par défaut par exemple) ou comportement (un display:none en React va carrément supprimer le nœud du DOM).

En fait, pas mal de comportements du DOM classique sont recodés en Javascript en React. Quand j'ai vu les onMouseEnter / onMouseLeave pour recréer le :hover j'étais assez dubitatif quand même. Le speaker annoncait que le fait d'être particulièrement explicite de cette manière rendait le code plus simple à comprendre. Je suis pas vraiment convaincu à premier abord, mais pourquoi pas. Par contre, là où je le rejoins c'est que ça rends le code de rendu vraiment plus facile à style. On peut écrire des tests unitaires qui vont pouvoir manuellement passer un élément en :hover et tester un comportement en allant regarder le contenu de l'objet de style.

Il a fini par nous expliquer deux-trois autres optimisation que le moteur de React opère. Pour moi, ce n'est rien de plus que ce que le moteur natif du browser execute, mais qu'ils ont recodé à la main, et ce qui leur permet de s'affranchir des différences d'implémentations entre navigateurs. Je ne sais pas trop quoi penser à ce sujet. Certes ça permet de simplifier le dev et d'offrir la même expérience à tout le monde, mais ça fait réinventer la roue.

Plus le talk avancait et plus les démonstrations allaient dans ce sens et j'en suis sorti en me demandant où ça allait exactement. Vjeux lui même annonçait que React était jeune, qu'ils ne s'attendaient pas à ce qu'il prenne autant d'ampleur en dehors de Facebook et qu'ils expérimentent des choses, mais que tout ne sera peut-être pas bon à garder.

Conclusion

Premier avant-gout de React, j'ai été assez séduit par la simplicité qui s'en dégage. La dernière conférence m'a laissé plutot dubitatif (comme à chaque fois qu'on essaie de remplacer CSS par JS parce que "CSS c'est trop compliqué").