Como diminuir o bundle e aumentar a performance de execução em aplicações frontend?
Você já recebeu uma tarefa para “otimizar o desempenho” de um aplicativo ou site? Neste artigo vamos conversar um pouco sobre as estratégias para diminuir o tamanho do seu aplicativo, a importância de se preocupar em atender diversos tipos de dispositivos, sobre Server-side rendering e um pouco sobre Gzip. Vamos lá!
O bundle que ninguém conhece!
Muitas vezes ao iniciar na programação, estamos mais focados em criar funcionalidades novas para o sistema. Mas a partir do momento que começamos a evoluir nossas skills, precisamos olhar além do código! O que isso significa? Bom, precisamos entender mais sobre como podemos melhorar a performance, segurança e o tamanho que nosso aplicativo ocupa em memória no frontend e em dispositivos mobile. Mas muitos desenvolvedores ainda não sabem o quanto de bundle o produto no qual trabalham possui. Isso é muito ruim para todos, é possível melhorar!
Como saber o tamanho do bundle?
No Angular você pode ter uma noção do tamanho do bundle final utilizando o comando n CLI:
ng build --prod
O bundle gerado localmente no arquivo main foi de 1.15MB.
No ReactJS a maneira mais fácil de ver o tamanho do pacote do seu aplicativo é abrir a guia de rede nas ferramentas de desenvolvimento do navegador e carregar seu aplicativo. Você deve ver dois arquivos JavaScript sendo carregados. O tamanho do pacote no modo de desenvolvimento será muito maior do que no modo de produção, então não se assuste se parecer enorme!
Existem algumas ferramentas que podem ajudá-lo a visualizar quais bibliotecas compõem seu pacote.
Se você estiver usando create-react-app, ele suporta o uso de source-map-explorer
.
No entanto, acredito que o webpack-bundle-analyzer
é a melhor ferramenta para analisar pacotes.
Como determinar se o Bundle está muito acima?
A nova linha de base global deixa espaço para ~100KiB (gzipped) de HTML/CSS/fontes e 300-350KB de JavaScript (compactado). - Alex Russell - Microsoft Partner PM on Edge
Com base na frase acima, a maioria dos aplicativos corporativos de médio porte pode ter o main.js
menor que 500 KB. Se o tamanho do seu pacote exceder amplamente esses números, talvez seja necessário procurar o que melhorar. Se o tamanho do seu pacote estiver abaixo desse número, talvez ainda queira otimizá-lo ainda mais.
Na imagem que vimos o aplicativo tem um main.js
de 1.15MB. Mas calma, isso não vai ser descarregado no browser do cliente. Na verdade o arquivo final gzip tem apenas cerca de 20% do tamanho do arquivo original, o que pode diminuir drasticamente o tempo de carregamento inicial do seu aplicativo.
O que é esse tal de gzip?
É um formato de arquivo usado para compactar e descompactar arquivos. Ele é baseado no algoritmo Deflate que permite que os arquivos sejam menores em tamanho, o que permite transferências de rede mais rápidas. O gzip é suportado por servidores web e navegadores modernos, o que significa que os servidores podem compactar arquivos automaticamente com gzip antes de enviá-los e os navegadores podem descompactar arquivos ao recebê-los.
Você pode localiza-lo no cabeçalho (header) de resposta. Se você abrir o navegador, abrir um site e ir até o console de desenvolvimento, na aba Rede (Network), verá um Content-Encoding: gzip.
Se você não vê este cabeçalho, seu navegador carregará os arquivos originais daquele site.
Mas como podemos garantir que este recurso vai estar habilitado?
Se hospeda seu aplicativo na maioria das plataformas de nuvem ou CDN, eles já fazem isso por automaticamente. Podemos ter como exemplo a própria AWS, então se estiver utilizando esses serviços, não se preocupe em ter que habilita-lo manualmente, pois eles provavelmente cuidaram disso para seu aplicativo web.
Se estiver utilizando um servidor IIS, pode ser que esse recurso esteja desativado. Mas normalmente as configurações padrões definem como habilitadas. Caso esse não seja seu caso, veja como habilitar no IIS:
Verificar as opções abaixo no módulo IIS Compression. 👇🏼
Se não houver módulo de compactação no IIS, habilite-o nos recursos do Windows. 👇🏼
Depois habilitar no site do IIS, pode conferir ao abrir a aba de rede do console do desenvolvedor para verificá-lo, o campo terá o sinal “GZip”.
Utilizando o Webpack Bundle Analyzer
Se o tamanho do seu pacote ficar muito grande, você pode analisar mais afundo o bundle. Alguns motivos podem estar relacionados a pacotes de terceiros de tamanho inadequado ou também pode ter esquecido de remover algum pacote que não está mais utilizando. O webpack tem um recurso incrível para nos dar uma ideia visual:
Para obter este relatório do bundle de sua aplicação basta seguir os passos abaixo:
npm install -g webpack-bundle-analyzer
No seu aplicativo, no caso Angular, execute
ng build --stats-json
(não use a flag --prod). Ao habilitar--stats-json
obterá um arquivo adicional chamadostats-es2015.json
dentro da pasta dist.Por fim, execute
webpack-bundle-analyzer pasta-que-foi-salva/stats-es2015.json
e seu navegador exibirá a página em localhost:127.0.0.1 ou 8888.
Certo, mas pode se perguntar: Como essa ferramenta pode ser útil? Vamos listar alguns pontos:
Ela te mostra o nome de Bibliotecas que você provavelmente vai olhar e se perguntar: Isso ainda está aqui?
Vai analisar que alguns pacotes são muito maiores do que o time realmente imaginava e podem ser substituídos por outros mais precisos.
Terá uma visão completa de tudo o que foi gerado da sua aplicação. Isso vai te ajudar a fazer boas escolhas e entender se alguns arquivos podem ser melhorados ou não.
Não perca o controle do bundle!
Aqui podemos destacar dois pontos. Existem inúmeras bibliotecas que contém códigos prontos. Realmente muitas ajudam e facilitam a nossa vida. Mas precisamos ter muito cuidado. Se dependermos constantemente de bibliotecas, vamos estar cometendo dois grandes erros: Fazer com que nossa aplicação dependa constantemente de Libs externas e o bundle vai aumentar consideravelmente o tempo de download.
Por isso o alerta é para ser cauteloso ao escolher bibliotecas de terceiros.
Fique atento com os tempos de download e execução
Os tempos de download são críticos para redes de baixo custo. Apesar do crescimento em 4G e até 5G em todo o mundo, nossos tipos de conexão eficazes permanecem inconsistentes. Muitas pessoas ainda utilizam 3G.
Outro detalhe, o tempo de execução do JavaScript é importante para smartphones com CPUs lentas. Devido às diferenças na CPU, GPU e limitação térmica, existem enormes diferenças entre o desempenho de smartphones de última geração com os de 4 anos atrás. Isso é importante para o desempenho do JavaScript, pois a execução é vinculada à CPU. Uma imagem de 170 KB pode ser baixada ao mesmo tempo que o script JavaScript de mesmo tamanho, mas será processada muito mais rápido que o script, pois as imagens são decodificadas e pintadas muito mais rápido do que o script é analisado, compilado e executado.
Veja na imagem abaixo o tempo de execução do site Reedit:
A imagem acima é original do blog v8.dev
Por isso é importante minimizar o tamanho do pacote JavaScript, especialmente para dispositivos móveis.
Ok, mas surge outra pergunta: Mas e o cache? Não podemos adotar essa estratégia?
A resposta é sim! Principalmente quando sabemos que algumas informações não vão ser atualizadas tão cedo. Mas fique atento a estratégia que está utilizando! Querendo ou não certos tipos de cache podem ser uma boa dor de cabeça no futuro.
Utilize ferramentas para analisar o tamanho do seu bundle
Use o plug-in Import Cost no VSCode para ficar atento ao tamanho das bibliotecas de terceiros enquanto está programando:
Com esse plug-in, você pode definir limites para o que é considerado um pacote pequeno ou médio:
"importCost.smallPackageSize": 15,
"importCost.mediumPackageSize": 50,
Utilize se for necessário o SSR
Devemos renderizar o conteúdo principal o mais rápido possível.
Para páginas orientadas a conteúdo, é melhor optar por renderização no lado do servidor (SSR). Os aplicativos de página única são adequados para aplicativos com longos tempos de sessão ou interfaces que transitam sem problemas (por exemplo, carrinhos de compras), mas, ao mesmo tempo, devemos mostrar o conteúdo rapidamente. Renderize no lado do servidor quando puder. O Angular tem uma ferramenta pronta para isso chamada Angular Universal. Executada no servidor, gera páginas estáticas de aplicativos que posteriormente são inicializadas no cliente. Isso significa que o aplicativo geralmente é renderizado mais rapidamente, dando aos usuários a chance de visualizar o layout do aplicativo antes que ele se torne totalmente interativo. Assim se evita que o usuário fique vendo apenas uma página em branco.
Abaixo segue a CLI do framework Angular que você pode instalar e testar para entender melhor como usar:
@nguniversal/express-engine
Estou pulando algumas etapas da instalação deste pacote para que o artigo não fique muito longo. O ponto é que rodando o comando ng serve -o
que é o modo tradicional do Angular, com a renderização realizada no cliente, poderá comparar com o comando com npm run dev:ssr
. Neste modo executaremos a renderização em um servidor express e poderemos ver os efeitos do SSR.
E como podemos ver essas diferenças?
Inspecionando o código fonte e comparando os dois modos que foram executados, verá que o que temos é mais código redenrizado, o que evita o carregamento de JavaScript. Assim o ajudamos ao usuário a evitar ficar olhando para uma pagina em branco, dependendo da velocidade da internet.
E qual a principal vantagem de utilizar SSR?
A principal é que quando utilizamos a renderização no lado do cliente (com SPA), sempre que o usuário acessar nossa aplicação, o browser irá baixar todo o JavaScript e processá-lo para renderizar o conteúdo da página. Porém, caso seja uma renderização relativamente complexa, este processo pode demorar alguns milissegundos que fazem toda a diferença na experiência do usuário. Utilizando SSR, é possível fornecer um primeiro conteúdo, já renderizado, muito rapidamente para o usuário, enquanto o restante do conteúdo é carregado e processado.
Utilize o ESLINT
Se sua aplicação é grande e complexa, e a equipe precisa manter tudo nos trilhos, você pode utilizar uma solução para isso. O ESLINT permite que utilizemos a flag no-restricted-imports
para avisar ou dar erro quando um pacote restrito for incluído.
Mas por que utilizar essa estratégia?
Algumas importações podem não fazer sentido em um ambiente específico. Por exemplo, o módulo do Node.js
fs
não faria sentido em um ambiente que não tivesse um sistema de arquivos.Alguns módulos fornecem funcionalidades semelhantes ou idênticas, pense lodashe underscore. Seu projeto não precisa de duas bibliotecas que fazem a mesma coisa. Normalmente quando se encontra algo do tipo, faltou critério dos desenvolvedores ao escolherem uma solução.
{
"rules": {
"no-restricted-imports": [
"error",
{
"paths": [
{
"name": "moment",
"message": "Use date-fns em vez de. See https://bundlephobia.com/package/moment"
}
]
}
]
}
}
Coloque em prática!
Depois de analisar todos esses tópicos, é importante que coloquemos em prática, estudando e analisando com o time de desenvolvimento, quais as melhores ferramentas e estratégias para melhorar a perfomance e execução de nossos apps em diversos dispositvos. Muito provavelmente será um tempo de analise da aplicação como um todo, tentativa e erro, mas também de muitos acertos! É importante destacar que existem contextos que devemos levar em consideração, número de usuários, segmento de negócio que sua aplicação atualmente está, posição no mercado, feedback de usuários e também da equipe de negócios. A solução que adotei para o App1 pode não ser a melhor para o App2! Mas sempre faça o melhor! Isso será notado!
Conclusão
Vimos pontos importantes de atenção que devemos ter em mente ao trabalhar na construção de aplicativos Web. Temos uma responsabilidade muito grande! Principalmente quando trabalhamos com Softwares que impactam milhões de pessoas. Devemos sempre procurar estratégias adequadas, estuda-las e testa-las para que possamos melhorar os produtos digitais de nossos clientes!
Espero que este artigo possa te ajudar a saber lidar com essas decisões que nós temos que tomar. Fico à disposição para contato no LinkedIn. Criticas construtivas são sempre bem-vindas! Até o proximo!
Referência: