Traduzindo modelos de poeira para JSX



Olá Habr! Sou Miloš, do Badoo, e este é meu primeiro post sobre o Habr, publicado originalmente em nosso blog de tecnologia . Espero que você goste e compartilhe e comente se tiver alguma dúvida

Então ... Reaja, amirita ???

Ele apareceu no meio da década (atormentado pelas intermináveis ​​guerras do framework JavaScript), abraçou o DOM , chocou a todos ao misturar HTML com JavaScript e transformou o cenário de desenvolvimento da web além do reconhecimento.

Todas essas realizações, mesmo sem ser uma estrutura .

Ame ou odeie, o React faz um trabalho muito bem, e isso é um modelo de HTML. Juntamente com uma grande comunidade e um ecossistema saudável, não é difícil ver por que se tornou uma das bibliotecas JavaScript mais populares e influentes, se não a mais popular de todas.


Aqui na equipe da Web para dispositivos móveis, não seguimos nenhuma estrutura JS rigorosa - ou pelo menos nenhuma popular - e usamos uma combinação de tecnologias modernas e legadas. Embora isso funcione bem para nós, manipular o DOM geralmente é difícil, e queríamos aliviá-lo reduzindo o número de atualizações "manuais", aumentando a reutilização de código e nos preocupando menos com vazamentos de memória.

Depois de alguma investigação, o React foi considerado a melhor escolha e decidimos continuar.

Entrei para o Badoo no meio desse processo. Tendo inicializado e trabalhado em projetos do React anteriormente, eu estava ciente de seus prós e contras na prática, mas migrar um aplicativo maduro com centenas de milhões de usuários é um desafio completamente diferente.

Jsx


React combina HTML com JavaScript em um formato chamado JSX . Embora pareça uma linguagem de modelo, o JSX é na verdade apenas uma sintaxe ou açúcar sintático, se você quiser, para chamadas de React, com aparência muito semelhante ao HTML.

Nossos próprios arquivos HTML eram bem organizados, e a maior parte de nossa renderização era feita simplesmente como template.render() . Como podemos manter essa ordem e simplicidade ao mudar para o React? Para mim, à parte as dificuldades técnicas, uma idéia era óbvia: substituir nossas chamadas existentes pelo código JSX.

imagem


Após um planejamento inicial, tentei e encerrei uma ferramenta de linha de comando que executa duas coisas simples:

  1. Lê modelos referenciados no arquivo UI (JavaScript)
  2. Substitua as chamadas template.render() pelo conteúdo HTML

Obviamente, isso nos moveria apenas no meio do caminho, porque ainda teríamos que modificar o código HTML manualmente. Considerando o volume e o número de nossos modelos, eu sabia que a melhor abordagem seria algo automatizado. A ideia original parecia bastante simples - e, se puder ser explicada, poderá ser implementada.

Após a demonstração da ferramenta inicial para os colegas de equipe, o melhor feedback que recebi foi que existe um analisador disponível para o idioma de modelo que usamos. Isso significa que poderíamos analisar e traduzir código muito mais facilmente do que com expressões regulares , por exemplo. Foi quando eu realmente soube que isso iria funcionar!

imagem


Eis que, após vários dias, nasceu uma ferramenta para converter modelos do tipo Dust.js em HTML em código JSX React. Usamos o Dust, mas com uma ampla disponibilidade de analisadores, o processo deve ser semelhante para traduzir qualquer outro idioma popular de modelos.

Para mais detalhes técnicos, pule para a seção Código-fonte abaixo. Usamos ferramentas como o Esprima para analisar o código JS e um gerador de analisador PEG.js para analisar os modelos de poeira. No mais simples dos termos, trata-se de traduzir esse tipo de código de modelo:

 <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> 

ao seu código JSX equivalente:

 <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> 

Veja a comparação lado a lado aqui .

Depois disso, nosso processo foi bem direto. Convertemos automaticamente nossos modelos de um formato para outro e tudo funcionou conforme o esperado (obrigado, teste automatizado). Para começar, preservamos nossa antiga API template.render() para manter as alterações isoladas.

Obviamente, com essa abordagem, você ainda acaba com modelos e não com os componentes do React "adequados". O benefício real é que é muito mais fácil, se não trivial, mudar para React a partir de modelos que já são JSX, na maioria dos casos, simplesmente envolvendo um código de modelo em uma chamada de função.

Você pode pensar: por que não escrever novos modelos a partir do zero? A resposta curta é que não havia nada errado com nossos modelos antigos - nós simplesmente tínhamos muitos deles. Quanto a reescrevê-los e trabalhar para a verdadeira componenteização, essa é uma história diferente .



Alguns podem argumentar que o modelo de componente é apenas outra tendência que pode passar, então, por que se comprometer com ele? É difícil prever, mas uma resposta possível é que você não precisa . Se você iterar rapidamente, poderá experimentar opções diferentes, sem gastar muito tempo com nenhuma delas, até encontrar o formato que funciona melhor para sua equipe. Esse é um dos conceitos principais para nós no Badoo.

Com o surgimento do ES7 / 8 / Next, Elm e Reason, para não mencionar o TypeScript e soluções semelhantes, o código que antes era *.js está se tornando cada vez mais indistinguível do JavaScript, e essa tendência parece que deve continuar. Em vez de ficar impressionado com isso, por que não usar isso em nosso proveito?

Código aberto


No espírito de fazer uma coisa bem , criamos essas ferramentas internas em várias partes:

  1. dust2jsx - pacote responsável pela tradução real de dust to jsx
  2. ratt (Reagir todas as coisas) - ferramenta de linha de comando para ler / gravar arquivos no disco. Responsável por incluir modelos referenciados e usa dust2jsx internamente para transformar código

Inclusive temos essas ferramentas de código aberto - verifique-as, assim como outros materiais de código aberto em nossa página do GitHub . Contribua ou simplesmente deixe um comentário se achar que é útil.

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


All Articles