React ou Web Components? São duas soluções diferentes para problemas diferentes que não precisam ser antagônicas. A abordagem do React é sincronizar o DOM com os dados, enquanto Web Components oferecem encapsulação para elementos reutilizáveis. O primeiro é um framework de interface, o segundo são um conjunto de tecnologias nativas dos navegadores. São claramente duas abordagens distintas.
Apesar dessas diferenças, existem advogados dos dois lados promovendo vantagens e desvantagens das duas abordagens. Há quem diga que um irá substituir o outro e predominar no desenvolvimento. Porém, há também aqueles que entendem suas particularidades e entendem que cada uma tem seu propósito.
Jack Franklin é um engenheiro do Google, da equipe responsável pelas ferramentas de desenvolvimento do Chrome, especializado em performance. Em um artigo publicado na internet, ele explica por que largou o React em prol do uso de Web Components.
Com sua autorização, traduzimos e reproduzimos o artigo na íntegra:
“Há pouco mais de dois anos, deixei um cargo em uma startup com sede em Londres, onde liderava o desenvolvimento de um grande front-end de comércio eletrônico baseado em React para ingressar no Google e trabalhar no Chrome DevTools. Meu foco inicial era apresentar os Web Components como o novo bloco de construção fundamental de todos os novos recursos e interface do usuário do DevTools. Com o painel Recorder lançado recentemente junto com outros, agora existem grandes partes do DevTools que são quase exclusivamente Web Components.
Quando deixei meu papel focado no React para trás, esperava achar a transição difícil e sentir falta do que o React tinha a oferecer. Acabei achando a transição mais fácil do que o esperado e passei a realmente gostar de trabalhar mais perto dos primitivos da plataforma e manter mais controle sobre o software que escrevo e, neste post de blog, gostaria de compartilhar por que isso acontece.
Em primeiro lugar, porque algumas pessoas na internet gostam de se irritar com opiniões que podem não corresponder às suas, quero deixar claro o que esta postagem no blog não é:
- Não é uma chamada para que todos larguem imediatamente o React e mudem para os Web Components.
- Não é um post de blog declarando o React ‘morto’ ou a escolha errada para cada projeto.
- Não é uma postagem de blog declarando que os Web Components são a melhor solução para todos os projetos.
- Não é uma postagem de blog declarando que todos os frameworks da web são inúteis ou uma má escolha.
- Não é uma postagem de blog sugerindo que, porque essa abordagem funciona para mim e para a equipe em que estou no Google, ela funciona para você. Todos os projetos são diferentes e o Chrome DevTools quase certamente tem um conjunto diferente de requisitos e restrições para o seu projeto. E tudo bem 🙂
Esta postagem do blog deve ser lida como as reflexões de alguém que foi de trabalhar com o React todos os dias para uma fase em que nem toco nele, e as experiências dessa transição. Estou escrevendo este post porque fiquei agradavelmente surpreso com o quanto gostei de trabalhar mais de perto com a plataforma web.
Embora eu use “React” como minha comparação, você pode substituí-lo razoavelmente por qualquer um dos grandes frameworks modernos.
Usando a plataforma
‘Usar a plataforma’ tornou-se uma frase um pouco usada demais e abusada nos últimos anos, mas o princípio básico ressoa em mim: podemos usar as APIs incorporadas ao navegador e JavaScript para criar recursos para nossos usuários sem pagar o custo de dependências de terceiros?
Nota: a resposta aqui nem sempre é 'sim'! Ainda há muitos recursos que eu gostaria de ver incorporados aos navegadores, mas, em comparação com dez anos atrás, o cenário da funcionalidade nativa se expandiu enormemente.
Um exemplo clássico aqui é a construção de formulários: esse costumava ser um motivo justificável para usar o React porque os navegadores nos ofereciam muito pouco além da funcionalidade primitiva. Alguns anos depois, em um projeto paralelo recente, consegui usar funcionalidade 100% nativa para criar meu formulário com uma experiência de usuário sólida:
- Usei atributos de validação de HTML para impor campos obrigatórios (e poderia ter feito mais com validação baseada em padrão)
- Usei a API FormData para ler valores fora do formulário ao invés de rastrear seus valores no estado (o que não precisei, pois a validação foi feita pelo navegador).
- Se eu quisesse, poderia até personalizar as mensagens de erro usando a API Constraint Validation – uma API que eu nem sabia que existia até alguns dias atrás!
Isso foi um pouco mais trabalhoso do que usar uma biblioteca do npm que resolve tudo isso para mim? Pode ser! Mas consegui obter o mesmo resultado, escrevendo algumas linhas extras de código sozinho, mas sem sobrecarregar meu aplicativo com uma dependência extra.
Mantendo o controle
Ajustar-se aos Custom Elements foi a principal preocupação que tive ao sair do React, mas passei a gostar muito de trabalhar com eles.
Custom Elements podem levar à escrita de mais código, mas, com um pouco de trabalho, você pode criar algo que parecerá surpreendentemente familiar se você já trabalhou com qualquer uma das bibliotecas de componentes populares, com uma diferença crucial: você não abre mão do controle .
O React não permitirá que você dite como e quando renderizar seu componente na página. Você escreve código usando suas construções e determina quando renderizar. 9 vezes em 10 – até 99 em 100 ou mais – isso funciona exatamente como você esperaria. Mas a plataforma web não é perfeita, e eu suspeito que a maioria dos desenvolvedores React já se deparou com uma situação em que você adoraria poder apenas ajustar como seu componente está sendo renderizado.
Desistir do controle do processo de renderização pode causar confusão, conforme este tweet de Gary Bernhardt:
Esse comportamento agora mudou no React v18, mas o fato de o React ter que trabalhar para suprimir chamadas extras de console.log que ocorrem como resultado de como ele renderiza meu aplicativo é surpreendente para mim; é essa falta de controle em meu próprio aplicativo que se tornou algo que me preocupa.
No desenvolvimento de software, isso é conhecido como Inversão de Controle. Quando você usa um framework como o React, seu código não está mais no controle direto de quando os componentes (ou funções) são chamados. Seus componentes não dizem diretamente ao React quando renderizá-los novamente, mas o React decide. Seus componentes cederam o controle ao React.
Nossa solução Custom Elements não tem esse investimento de controle; controlamos cada renderização chamando explicitamente uma função (no caso de lit-html, é um literal de modelo marcado chamado html).
A desvantagem de não escolher um framework como o React é que você deve considerar a recriação de peças que já estão integradas, como um agendador básico que garante renderizações em lote ou uma biblioteca de auxiliares de teste para facilitar o teste desses componentes. Você deve considerar cuidadosamente suas opções em situações como esta: se evitarmos o React, mas acabarmos reimplementando a maior parte do que ele oferece, talvez fosse melhor usar o framework. No nosso caso, ainda achamos que essa decisão foi justificada porque não precisamos recriar um escalonador com toda a complexidade do React; podemos construir uma implementação pequena e independente que apenas implemente o que precisamos.
Tendo construído nosso agendador básico, sabemos exatamente por que e quando cada componente é renderizado, e nos momentos em que temos que desviar do caminho padrão, somos capazes de fazê-lo. Isso parece muito valioso: todo projeto de software em que já trabalhei tinha pelo menos um componente que precisava fazer algo diferente para resolver um caso peculiar e específico.
Escolha dependências que podem ser facilmente substituídas
Uma área em que faltam elementos personalizados é alguma forma de solução de modelo HTML que forneça uma nova renderização eficiente de HTML. Eu definitivamente recomendo usar uma biblioteca para isso, e optamos por lit-html. O que atrai no lit-html é que ele constitui apenas uma pequena parte da nossa solução. Poderíamos ter optado pelo Lit, uma biblioteca de componentes com mais recursos formada em torno de elementos personalizados, mas isso nos levaria a aumentar nossas dependências e abrir mão de algum controle (para reiterar os pontos que fiz anteriormente nesta postagem do blog: isso não é uma crítica de Lit, e para muitas pessoas a Lit é a escolha certa!).
Lit-html garante que nosso HTML seja renderizado de forma eficiente e vem com um bom conjunto de diretivas que nos permite realizar facilmente tarefas comuns, como aplicar classes condicionalmente. Não é tão perfeito quanto o JSX, mas chega bem perto.
A melhor parte? É uma dependência muito pequena (3,3 kB gzipada) e, ainda mais importante, poderia ser facilmente substituída se necessário. Pode soar negativo ou até pessimista, mas quando adotamos uma nova dependência uma das principais perguntas que fazemos é ‘o que acontece se isso desaparecer’?
Digamos que o React desapareça (isso não quer dizer que eu acho que vai). Qual é o custo para nós de lidar com isso? Temos algumas opções:
- Manter um fork do React em qualquer versão que estejamos usando no momento.
- Migrar todos os nossos componentes do React para outra coisa.
Nenhuma dessas opções me atrai; manter uma biblioteca significa que não fazemos nada e perdemos melhorias e/ou correções de segurança, e migrar todos os nossos componentes seria um grande empreendimento. Tenho certeza de que os forks do React surgiriam caso esse evento ocorresse, mas, independentemente disso, envolveria muita rotatividade e trabalho para colocar as coisas em uma base mais saudável. Migrar todos os nossos componentes seria um exercício caro com poucos benefícios tangíveis para os usuários finais – e, portanto, uma venda incrivelmente difícil para os negócios e a liderança. Também teríamos que aprender um novo framework (mesmo que fosse semelhante ao React) e aumentar nossa experiência nesse framework.
Compare isso com elementos personalizados e lit-html. Podemos ter um bom nível de confiança de que os elementos personalizados não desaparecerão repentinamente; É incorporado ao navegador e a compatibilidade com versões anteriores é um princípio fundamental da plataforma da web.
Se você está pensando em elementos personalizados v0 sendo removidos em favor de v1, lembre-se de que v0 era uma especificação experimental específica do Chrome, enquanto v1 é uma especificação padronizada de plataforma cruzada. O objetivo da v0 era coletar feedback dos desenvolvedores que pudessem informar a futura especificação padronizada.
E se o lit-html desaparecesse da internet? Temos as mesmas duas opções: manter um fork ou substituí-lo. Manter um fork não seria ideal pelas mesmas razões que manter um fork do React não é ideal, com uma pequena diferença: o escopo do lit-html é muito menor e é uma biblioteca muito menor geralmente. Seria menos trabalhoso pensar e aprender até o ponto em que poderíamos fazer correções ou melhorias, se necessário.
Substituir o lit-html seria uma demanda, mas muito menor do que substituir o React: ele é usado em nossa base de código apenas para que nossos componentes (re)renderizem o HTML. Substituir lit-html ainda significaria que podemos manter nossa lógica de negócios, mantendo o valor que eles fornecem aos usuários finais. Lit-Html é um pequeno tijolo Lego em nosso sistema, React (ou Angular, ou similar) é a caixa inteira.
O custo de dependências de terceiros
As dependências de terceiros, grandes ou pequenas, têm um conjunto de custos que seus usuários e/ou desenvolvedores pagarão. A opinião de todos sobre se esse custo vale a pena ou não vai diferir, e vai depender do seu aplicativo e sua tech stack, mas quando penso em adicionar novas dependências, aparece o seguinte conjunto de custos:
- Tamanho do pacote: quanto peso essa dependência está adicionando ao nosso JavaScript final que temos que entregar e executar no navegador? Esse tamanho de pacote é apropriado e vale a pena para o que essa dependência oferece?
- Mudanças e atualizações de última hora: o que acontece se o pacote tiver uma grande revisão e precisar ser atualizado para a versão mais recente? Permanecemos na versão mais antiga (não é ideal se não estiver recebendo atualizações ou correções de segurança) ou investimos o trabalho para atualizar? O trabalho de atualização pode ser priorizado em breve ou é o tipo de trabalho que talvez nunca tenhamos?
- Risco de código ou problemas não mantidos: quem pode dizer que uma dependência de terceiros pode ter uma vulnerabilidade ou problema específico que pode causar problemas? (isso não é uma crítica a todos aqueles que trabalham incansavelmente para manter o software de código aberto – mas essas coisas acontecem).
Jeremy Keith em seu recente post sobre confiança afirma:
‘Cada dependência que você adiciona a um projeto é mais um ponto único potencial de falha’.
Jeremy Keith
O mesmo se aplica ao seu próprio código (troque “dependência” por “arquivo”), mas, crucialmente, você tem controle total, presumivelmente está mais familiarizado com seu funcionamento, pois foi escrito internamente e não está em dívida com outros para consertar a questão. Isso não quer dizer que você deva recriar o mundo em cada projeto; sempre haverá um bom equilíbrio entre construí-lo sozinho e adicionar uma dependência, e não há regra que determine o resultado certo todas as vezes.
Conclusão
Este post não quer dizer que você não deve buscar dependências. Em resposta à postagem de Jeremey Keith sobre confiança e dependências de terceiros, Charles Harries sugere que a compatibilidade entre navegadores foi historicamente o motor para dependências:
‘A compatibilidade do navegador é uma das promessas subjacentes que as bibliotecas – especialmente as grandes que Jeremy faz referência, como React e Bootstrap – fazem aos desenvolvedores.
(…) Estou com um orçamento limitado e não posso gastar meu tempo lendo a página caniuse.com para Array.prototype.includes ou MutationObserver. O Lodash promete compatibilidade entre plataformas bem na parte inferior de sua página inicial.
Charles Harries
Concordo plenamente com a opinião de Charles, e esta é uma área em que trabalhar no DevTools para um navegador tem uma vantagem porque conhecemos a escolha do navegador do nosso público.
Minha esperança é que, com o conjunto de recursos básicos suportados pelos navegadores agora mais uniformes – especialmente com a morte do Internet Explorer – que nós, como indústria, possamos com o tempo passar a alcançar a extensa funcionalidade integrada dos navegadores por padrão, usando polyfilling quando absolutamente necessário e olhar além dos frameworks como um ponto de partida padrão.
Publicado originalmente como “Why I don’t miss React: a story about using the platform” em 3 de maio de 2022. Traduzido e republicado com autorização do autor.