Traduction de modèles Dust en JSX



Bonjour Habr! Je suis Miloš de Badoo, et ceci est mon premier article Habr, initialement publié sur notre blog technologique . J'espère que vous l'aimez, et veuillez partager et commenter si vous avez des questions

Alors ... Réagissez, amirite ???

Il est apparu au milieu de la décennie (en proie aux guerres interminables du framework JavaScript), a embrassé le DOM , a choqué tout le monde en mélangeant HTML avec JavaScript et a transformé le paysage du développement Web au-delà de la reconnaissance.

Toutes ces réalisations, sans même être un cadre .

Aimez-le ou détestez-le, React fait très bien un travail, et c'est le modèle HTML. Avec une grande communauté et un écosystème sain, il n'est pas difficile de comprendre pourquoi elle est devenue l'une des bibliothèques JavaScript les plus populaires et les plus influentes, sinon la plus populaire de toutes.


Ici, au sein de l'équipe Web mobile, nous ne suivons aucun framework JS strict - ou du moins, un framework populaire - et nous utilisons un mélange de technologies héritées et modernes. Bien que cela fonctionne bien pour nous, la manipulation du DOM est généralement difficile, et nous voulions y remédier en réduisant le nombre de mises à jour "manuelles", en augmentant notre réutilisation de code et en nous souciant moins des fuites de mémoire.

Après une enquête, React a été considéré comme le meilleur choix et nous avons décidé d'y aller.

J'ai rejoint Badoo au milieu de ce processus. Ayant démarré et travaillé sur des projets React auparavant, j'étais conscient de ses avantages et inconvénients dans la pratique, mais la migration d'une application mature avec des centaines de millions d'utilisateurs est un défi complètement différent.

Jsx


React mélange HTML et JavaScript dans un format nommé JSX . Bien qu'il ressemble à un langage de modèle, JSX n'est en fait qu'une syntaxe ou un sucre syntaxique si vous voulez, pour les appels React, très similaire au HTML.

Nos propres fichiers HTML étaient bien organisés et la plupart de notre rendu a été fait aussi simplement que template.render() . Comment pourrions-nous conserver cet ordre et cette simplicité en passant à React? Pour moi, mis à part les difficultés techniques, une idée était évidente: remplacer nos appels existants par du code JSX.

image


Après une planification initiale, je l'ai essayé et j'ai terminé un outil de ligne de commande qui effectue deux choses simples:

  1. Lit les modèles référencés dans le fichier UI (JavaScript)
  2. Remplacez template.render() appels template.render() par le contenu HTML

Bien sûr, cela ne nous déplacerait qu'à mi-chemin, car il nous faudrait encore modifier le code HTML manuellement. Compte tenu du volume et du nombre de nos modèles, je savais que la meilleure approche serait quelque chose d'automatisé. L'idée originale semblait assez simple - et si elle peut être expliquée, elle peut être mise en œuvre.

Après avoir fait la démonstration de l'outil initial à ses coéquipiers, le meilleur retour que j'ai eu est qu'il y a un analyseur disponible pour le langage de template que nous avons utilisé. Cela signifie que nous pourrions analyser et traduire du code beaucoup plus facilement qu'avec des expressions régulières , par exemple. C'est à ce moment que j'ai vraiment su que ça marcherait!

image


Et voilà, après plusieurs jours, un outil est né pour convertir les modèles HTML Dust.js en code JSX React. Nous avons utilisé Dust, mais avec une large disponibilité d'analyseurs, le processus devrait être similaire pour la traduction de tout autre langage de modélisation populaire.

Pour plus de détails techniques, passez à la section Open-source ci-dessous. Nous avons utilisé des outils comme Esprima pour analyser le code JS et un générateur d'analyseur PEG.js pour analyser les modèles Dust. Dans le plus simple des termes, il s'agit de traduire ce type de code de modèle:

 <div class="encounters {?isExpanded}is-expanded{/isExpanded}"> {?showTooltip} <div class="tooltip"> <span>{#_t}{encounters_tooltip}{/_t}</span> <div class="icon"> {@Icon name="icon-encounters" size="stretch" /} </div> </div> {/showTooltip} <div class="images"> {#images} <img src="{src}"> <input type="radio" id="{id}" {?selected}checked{/selected} /> <label for="showme-{id}"> {name} </label> {/images} </div> <div class="footer"> {! encounters-footer template will be injected here !} </div> </div> 

à son équivalent de code JSX:

 <div className="encounters {props.isExpanded ? 'is-expanded' : ''}"> {props.showTooltip ? <div className="tooltip"> <span>{i18n.get('encounters_tooltip')}</span> <div className="icon"> <Icon name="icon-encounters" size="stretch" /> </div> </div> : null} <div className="images"> {props.images.map(item => <img src={item.src}> <input type="radio" id={`showme-${item.id}`} defaultChecked={item.selected ? true : undefined} /> <label htmlFor={`showme-${item.id}`}> {item.name} </label> )} </div> <div className="footer"> {/* encounters-footer template will be injected here */} </div> </div> 

Voir la comparaison côte à côte ici .

Après cela, notre processus a été assez simple. Nous avons automatiquement converti nos modèles d'un format à un autre, et tout a fonctionné comme prévu (merci, tests automatisés). Pour commencer, nous avons conservé notre ancienne API template.render() pour garder les modifications isolées.

Bien sûr, avec cette approche, vous vous retrouvez toujours avec des modèles et non des composants React «appropriés». Le véritable avantage réside dans le fait qu'il est beaucoup plus facile, sinon trivial, de passer à React à partir de modèles qui sont déjà JSX, dans la plupart des cas, en enveloppant simplement un code de modèle dans un appel de fonction.

Vous pourriez penser: pourquoi ne pas écrire de nouveaux modèles à partir de zéro? La réponse courte est qu'il n'y avait rien de mal avec nos anciens modèles - nous en avions simplement beaucoup. Quant à les réécrire et à travailler vers une véritable composanteisation, c'est une autre histoire .



Certains pourraient faire valoir que le modèle de composant n'est qu'une autre tendance qui pourrait passer, alors pourquoi s'y engager? C'est difficile à prévoir, mais une réponse possible est que vous n'êtes pas obligé de le faire . Si vous répétez rapidement, vous pouvez essayer différentes options, sans passer trop de temps sur l'une d'entre elles, jusqu'à ce que vous trouviez le format qui convient le mieux à votre équipe. C'est l'un des concepts clés pour nous chez Badoo.

Avec l'essor d'ES7 / 8 / Next, Elm et Reason, sans parler de TypeScript et de solutions similaires, le code qui était autrefois *.js devient de plus en plus impossible à distinguer de JavaScript, et cette tendance semble devoir se poursuivre. Au lieu d'être dépassé par cela, pourquoi ne pas l'utiliser à notre avantage?

Open source


Dans l'esprit de bien faire une chose , nous avons construit ces outils internes en plusieurs parties:

  1. dust2jsx - paquet responsable de la traduction réelle de la poussière en jsx
  2. ratt (React All The Things) - outil en ligne de commande pour lire / écrire des fichiers sur le disque. Responsable de l'inclusion de modèles référencés et utilise dust2jsx interne pour transformer le code

Nous avons même open-source ces outils - assurez-vous de les vérifier, ainsi que d'autres matériaux open-source sur notre page GitHub . Merci de bien vouloir contribuer ou simplement de nous laisser un commentaire si vous les trouvez utiles.

Source: https://habr.com/ru/post/fr437224/


All Articles