Pacote e desempenho de JavaScript: práticas recomendadas

Agora, na virada da década, é hora de reavaliar criticamente o que foi considerado correto no passado recente e descobrir se ele perdeu relevância hoje. As melhores práticas de ontem às vezes se tornam antipadrões de hoje.



O autor do artigo, cuja tradução estamos publicando hoje, explorará três abordagens para agrupar projetos JavaScript usando o exemplo de um aplicativo simples Hello World criado usando o React. Alguns dos exemplos que ele cita incluem a leitura dos conceitos básicos dos construtores de módulos, como o Webpack , que parece ser a ferramenta mais popular atualmente.

Abordagem nº 1: absolutamente tudo entra no pacote (parece uma grande bola de linha)


A idéia principal: não use essa abordagem.

Com essa abordagem, o construtor de módulos é simplesmente usado para empacotar tudo no pacote - dependências e código do aplicativo. A saída é algo como um grande novelo de lã. No meu exemplo, isso inclui react , react-dom e o código do próprio aplicativo. Um único pacote que contém todo o código do projeto está conectado à página:

 <!-- index.html --> <script src="bundle.[hash].min.js"></script> 

Antes do lançamento do HTTP / 2, esse padrão podia ser considerado, de alguma maneira, bastante aceitável, pois seu uso reduz o número de solicitações HTTP que o navegador executa ao carregar os materiais da página. Mas, como a maioria dos sites hoje usa HTTP / 2, esse padrão se tornou antipadrão.

Porque O fato é que, ao usar o HTTP / 2, a execução de muitas solicitações não cria mais a mesma carga no sistema como antes. Como resultado, compactar o código em um único pacote grande não oferece mais vantagens significativas ao projeto.

Com essa abordagem, a organização eficiente do cache do navegador é complicada. Por exemplo, alterar apenas uma linha de código em um aplicativo simples alterará o hash do pacote e invalidará o cache que armazena todo o código do projeto. Como resultado, todos os visitantes que retornam precisam fazer o download do código inteiro do site novamente, mesmo que esse código não seja 99% diferente do código baixado na visita anterior. Aqui estamos lidando com o uso irracional de recursos de rede devido à transmissão repetida dos mesmos dados do servidor para o cliente.

Hoje, o HTTP / 2 é suportado por mais de 95% dos clientes . Em 2019, esse protocolo foi implementado pela maioria dos servidores. Saiba mais sobre o uso do HTTP / 2 em 2019 aqui.

Abordagem nº 2: empacotamento separado do código do projeto e do código de bibliotecas de terceiros (separação de código)


Ideia principal: use esta abordagem.

Vamos levar em conta o que falamos na seção anterior e melhorar a situação com o cache do navegador, separando o código do projeto do código de dependência. Isso resolve o problema no caso descrito acima, quando alteramos ligeiramente o código do projeto e depois publicamos a atualização na produção. Agora, apenas o hash do pacote configurável do index , que armazena o código do projeto, foi alterado e o hash do pacote vendor do vendor permanece inalterado. Os visitantes que retornarem ao site atualizado farão download apenas do arquivo de index modificado com essa abordagem, o que economizará alguns recursos de rede.

Se falamos sobre o Webpack, para implementar essa estratégia, você precisará de configurações adicionais relacionadas à separação de código. Com a ajuda deles, informamos o bundler sobre onde está o código de dependência. Uma maneira simples e conveniente de detectar esse código é que existem node_modules no caminho para os arquivos correspondentes, pois todo o código de dependência é armazenado nesta pasta.

Aqui está o que o código de conexão do script se tornou:

 <!-- index.html --> <script src="vendor.[hash].min.js"></script> <script src="index.[hash].min.js"></script> 

E aqui está a linha do tempo em cascata para carregar a página, ao trabalhar com o qual o HTTP / 2 é usado.


Programação de carregamento de página em cascata

Este é um passo na direção certa. Mas podemos continuar otimizando o pacote. Se você pensar sobre tudo isso, poderá entender que algumas dependências do projeto mudam com menos frequência do que outras. Talvez react-dom menos provável que react e react-dom alterados e react quando uma biblioteca é atualizada, outra é atualizada. Como resultado, podemos concluir que essas duas bibliotecas podem ser agrupadas em um fragmento lógico, que pode ser separado de outras dependências, que mudam com mais frequência do que react e react-dom . Realizando essa ideia, obtemos o seguinte:

 <!-- index.html --> <script src="vendor.react.[hash].min.js"></script> <script src="vendor.others.[hash].min.js"></script> <script src="index.[hash].min.js"></script> 

Se continuarmos o desenvolvimento dessa idéia, podemos decidir que os visitantes do site talvez não precisem baixar todo o código do projeto para visualizar apenas uma página. No inverno, alguns de nós tendem a ganhar peso - e, portanto, o arquivo de index , que contém o código do aplicativo, aumenta com o tempo. Em algum momento, pode acontecer que o código do projeto esteja sujeito a uma separação mais justa, carregando dinamicamente componentes individuais e até organizando a pré-carga de módulos individuais.

Para mim, esse nível de separação de código ainda parece bastante assustador. Ainda parece uma tecnologia experimental (e algo assim, no qual erros sutis podem muito bem se manifestar). Mas está muito claro para mim que uma forte separação de código é a direção que o setor de desenvolvimento da web está seguindo. Talvez devido ao suporte do navegador para módulos JavaScript, eventualmente possamos abandonar completamente os empacotadores como o Webpack e simplesmente fornecer módulos de código individuais aos clientes. Será interessante ver aonde tudo isso nos leva!

Abordagem 3: Usando CDNs Públicas para o Código de Algumas Dependências


A idéia principal: não use essa abordagem.

Se você é um daqueles que é um pouco antiquado no desenvolvimento da Web (como eu), pode ter uma sensação interna de que podemos conectar o arquivo vendor.react , discutido na seção “Abordagem nº. 2 ", usando um recurso público da CDN:

 <!-- index.html --> <script crossorigin src="https://unpkg.com/react@16.12.0/umd/react.production.min.js"></script> <script crossorigin src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.production.min.js"></script> <script src="index.[hash].min.js"></script> 

Observo que, ao usar essa abordagem, é necessário informar ao coletor de projetos do Webpack que ele deve excluir o código de react e o código de react-dom do pacote.

À primeira vista, tudo isso parece bastante sólido, mas essa abordagem tem algumas desvantagens que proponho considerar.

▍ Menos # 1: Usando sites diferentes dos mesmos arquivos de dependência? Já não ...


Os desenvolvedores da velha escola mantêm a esperança de que, se todos os sites vincularem ao mesmo recurso da CDN e usarem a mesma versão do React que o nosso site, os visitantes do site, se já houver um código React no cache de seus navegadores, não perderá tempo recarregando-o. Isso aumentaria seriamente a velocidade de exibição de páginas do nosso site no modo de trabalho. Sim, e a documentação do React sobre esse assunto parece promissora. Portanto, com certeza, alguns desenvolvedores usam esse padrão. Certo?

Embora anteriormente isso pudesse funcionar, recentemente em navegadores, para aumentar a segurança, eles começaram a implementar um mecanismo de compartilhamento de cache. Estamos falando do fato de que, mesmo em condições ideais, quando dois sites usam a mesma biblioteca, carregados pelo mesmo link CDN, o código é baixado independentemente para cada domínio e o cache, por razões de privacidade, acaba na sandbox alocado para um domínio específico. Como se viu , esse mecanismo já foi implementado no Safari (aparentemente, existe desde 2013?!). E se falarmos sobre o Chrome 77, para ativar a separação de cache por enquanto, você precisa usar um sinalizador especial.

Supõe-se que o uso de CDNs publicamente disponíveis diminuirá à medida que o compartilhamento de cache for implementado em mais navegadores.

▍ Menos 2: desperdício de recursos do sistema em operações auxiliares (para cada domínio)


Aqui se expressa a idéia de que o uso da CDN leva a um aumento na carga no sistema, pois mesmo antes de enviar a solicitação HTTP, o navegador precisa resolver muitos problemas: resolução de nomes DNS, conexão TCP, handshake SSL. Para se conectar ao site, o navegador precisa executar essas ações em qualquer caso, mas se for forçado a se conectar à CDN, isso aumentará a carga nele.

Aqui está um gráfico em cascata que ilustra o processo de carregamento de uma página que usa scripts de um recurso CDN disponível ao público.


Linha do tempo em cascata para carregar uma página usando recursos CDN disponíveis ao público

As ovais vermelhas destacam as áreas nas quais ocorrem operações que precedem a execução de consultas. Parece um pouco demais para um aplicativo simples Hello World.

À medida que meu exemplo simples evolui e cresce, chegará um momento em que eu quero usar minha própria fonte nele. Por exemplo - extraído do Google Fonts. E isso significa que o número de tais atrasos aumentará apenas, pois você precisará se conectar ao domínio correspondente para baixar fontes. Aqui, a idéia de hospedar todos os recursos do site em seu próprio domínio principal (que, é claro, está localizado atrás do próprio recurso CDN do projeto baseado em Cloudflare ou Cloudfront) parece ser muito atraente.

Se, em nosso exemplo, mudarmos para o download de duas dependências do React do domínio principal do site, isso levará ao fato de que o agendamento em cascata do carregamento da página se tornará muito mais preciso.


Agenda de carregamento em cascata para uma página que não usa recursos CDN disponíveis ao público

▍Minus No. 3: usando diferentes versões de dependências por sites diferentes


Criei um pequeno estudo de pesquisa dos 32 maiores sites usando o React. Infelizmente, descobri que apenas 10% deles usam recursos da CDN disponíveis ao público para baixar o React. Porém, dadas as versões do React que todos os sites estudados usam, isso realmente não importa. Em um mundo ideal, não haveria separação do cache do navegador e todos os sites poderiam ser organizados e usar as mesmas versões de script das mesmas CDNs públicas. Na realidade, há uma variação extremamente forte nas versões do React usadas por diferentes sites. Isso destrói a ideia de um cache compartilhado do navegador.


Reagir versões usadas por sites diferentes

Se você abrir primeiro um site popular usando o React e depois outro, as chances de que esses dois sites usem a mesma versão do React são muito pequenas.

No decorrer da pesquisa, encontrei algumas informações mais interessantes sobre esses sites do React. Talvez eles também pareçam interessantes para você:

  • Em 2/3 sites, o Webpack é usado para criar código.
  • 87% dos sites usam HTTP / 2, que é mais do que o valor médio de 58%.
  • A maioria dos projetos (aproximadamente 56%) hospeda as próprias fontes.

Aqui estão os dados de origem da minha experiência.

▍Minus No. 4: problemas de não desempenho


Infelizmente, hoje em dia, aqueles que usam recursos CDN disponíveis ao público enfrentam não apenas problemas relacionados à velocidade de carregamento da página, mas também alguns outros problemas:

  • Questões de segurança. Existem problemas de segurança associados ao uso de recursos CDN disponíveis ao público, além daqueles destinados a resolver o compartilhamento de cache nos navegadores. Se, por exemplo, os hackers invadirem um recurso de CDN acessível ao público, poderão injetar muito cuidadosamente código JavaScript malicioso nas bibliotecas. Esse código terá todos os privilégios do código do site executado no cliente e poderá trabalhar com os dados dos usuários que efetuaram login no site.
  • Questões de privacidade. Muitas empresas coletam dados do usuário de solicitações feitas por recursos de terceiros. Em teoria, se o uso de um recurso da CDN disponível ao público para o download de código ou fontes de dependência for implementado em todos os sites, esse recurso da CDN poderá rastrear as sessões do usuário e os recursos de seu trabalho na Internet. Um recurso semelhante poderá fazer suposições sobre o que lhes interessa (por exemplo, para fins de publicidade). E tudo isso - sem o uso de cookies!
  • Ponto único de falha. A distribuição dos materiais necessários para o funcionamento do site em vários domínios aumenta as chances de que, devido a problemas em um desses domínios, o cliente possa baixar apenas parte dos materiais necessários para colocar as páginas em condições de funcionamento. Para ser honesto, esses problemas podem ser resolvidos usando JavaScript, mas, para isso, o desenvolvedor do site precisará fazer alguns esforços adicionais.

Sumário


É muito óbvio que o futuro está na abordagem nº 2.

Hospede seus próprios recursos CDN na frente de seus servidores usando HTTP / 2 (como Cloudflare ou Cloudfront). Divida o código em pequenos fragmentos para usar efetivamente o cache do navegador. No futuro, os fragmentos nos quais o código do site é dividido podem se tornar ainda menores, atingindo o tamanho de módulos JavaScript individuais, devido ao fato de os navegadores começarem a implementar o suporte a essa tecnologia.

Caros leitores! Você usa tecnologias de separação de código em seus projetos da web?

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


All Articles