
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.
Après une planification initiale, je l'ai essayé et j'ai terminé un outil de ligne de commande qui effectue deux choses simples:
- Lit les modèles référencés dans le fichier UI (JavaScript)
- 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!
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:
- dust2jsx - paquet responsable de la traduction réelle de la poussière en jsx
- 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.