Neste codelab, vamos melhorar o desempenho do seguinte aplicativo removendo dependências não usadas e desnecessárias.
Medir
É sempre bom medir o desempenho de um site antes de adicionar otimizações.
- Para visualizar o site, pressione Ver app e depois Tela cheia
.
Clique no gatinho que você mais gosta. O Realtime Database do Firebase é usado neste aplicativo. Por isso, a pontuação é atualizada em tempo real e sincronizada com todas as outras pessoas que usam o aplicativo. 🐈
- Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir o DevTools.
- Clique na guia Rede.
- Marque a caixa de seleção Desativar cache.
- Recarregue o app.
Quase 1 MB de JavaScript está sendo enviado para carregar esse aplicativo simples.
Confira os avisos do projeto no DevTools.
- Clique na guia Console.
- Verifique se
Warnings
está ativado no menu suspenso de níveis ao lado da entradaFilter
.
- Confira o aviso exibido.
O Firebase, uma das bibliotecas usadas neste aplicativo, está sendo um bom samaritano ao fornecer um aviso para informar aos desenvolvedores que não importem todo o pacote, mas apenas os componentes usados. Em outras palavras, há bibliotecas não utilizadas que podem ser removidas desse aplicativo para que ele carregue mais rápido.
Há também casos em que uma biblioteca específica é usada, mas pode haver uma alternativa mais simples. O conceito de remoção de bibliotecas desnecessárias será abordado mais adiante neste tutorial.
Analisar o pacote
Há duas dependências principais no aplicativo:
- Firebase: uma plataforma que oferece vários serviços úteis para aplicativos iOS, Android ou da Web. Aqui, o Realtime Database é usado para armazenar e sincronizar as informações de cada gatinho em tempo real.
- Moment.js: uma biblioteca de utilitários que facilita o
processamento de datas em JavaScript. A data de nascimento de cada gatinho é armazenada no banco de dados do Firebase, e
moment
é usado para calcular a idade em semanas.
Como apenas duas dependências podem contribuir para um tamanho de pacote de quase 1 MB? Um dos motivos é que qualquer dependência pode ter as próprias dependências. Portanto, há muito mais do que apenas duas se cada profundidade/ramificação da "árvore" de dependência for considerada. É fácil um aplicativo ficar grande relativamente rápido se muitas dependências forem incluídas.
Analise o pacote para ter uma ideia melhor do que está acontecendo. Há várias ferramentas criadas pela comunidade que podem ajudar, como o webpack-bundle-analyzer
.
O pacote dessa ferramenta já está incluído no app como um devDependency
.
"devDependencies": {
//...
"webpack-bundle-analyzer": "^2.13.1"
},
Isso significa que ele pode ser usado diretamente no arquivo de configuração do webpack.
Importe-o no início de webpack.config.js
:
const path = require("path");
//...
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
.BundleAnalyzerPlugin;
Agora adicione-o como um plug-in no final do arquivo dentro da matriz plugins
:
module.exports = {
//...
plugins: [
//...
new BundleAnalyzerPlugin()
]
};
Quando o aplicativo for recarregado, você verá uma visualização do pacote inteiro em vez do app.
Não é tão fofo quanto ver alguns gatinhos 🐱, mas é incrivelmente útil. Ao passar o cursor sobre qualquer um dos pacotes, o tamanho dele é representado de três maneiras diferentes:
Tamanho da estatística | Tamanho antes de qualquer minificação ou compactação. |
---|---|
Tamanho analisado | Tamanho do pacote real no pacote após a compilação. A versão 4 do webpack (usada neste aplicativo) minimiza os arquivos compilados automaticamente. Por isso, o tamanho é menor do que o tamanho da estatística. |
Tamanho compactado com Gzip | Tamanho do pacote após a compactação com codificação gzip. Esse assunto é abordado em um guia separado. |
Com a ferramenta webpack-bundle-analyzer, é mais fácil identificar pacotes não usados ou desnecessários que representam uma grande porcentagem do pacote.
Remover pacotes não utilizados
A visualização mostra que o pacote firebase
consiste em um lote muito mais do que apenas um banco de dados. Ele inclui pacotes adicionais, como:
firestore
auth
storage
messaging
functions
Esses são todos serviços incríveis fornecidos pelo Firebase (consulte a documentação para saber mais), mas nenhum deles está sendo usado no aplicativo. Portanto, não há motivo para importar todos eles.
Reverta as mudanças em webpack.config.js
para ver o aplicativo novamente:
- Remova
BundleAnalyzerPlugin
na lista de plug-ins:
plugins: [
//...
new BundleAnalyzerPlugin()
];
- Agora remova a importação não utilizada da parte de cima do arquivo:
const path = require("path");
//...
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
O aplicativo deve carregar normalmente agora. Modifique src/index.js
para atualizar as
importações do Firebase.
import firebase from 'firebase';
import firebase from 'firebase/app';
import 'firebase/database';
Agora, quando o app é recarregado, o aviso do DevTools não aparece. Abrir o painel Rede do DevTools também mostra uma boa redução no tamanho do pacote:
Mais da metade do tamanho do pacote foi removida. O Firebase oferece muitos serviços
diferentes e dá aos desenvolvedores a opção de incluir apenas aqueles que são realmente
necessários. Neste aplicativo, apenas firebase/database
foi usado para armazenar e sincronizar
todos os dados. A importação firebase/app
, que configura a superfície da API para cada um dos diferentes serviços, é sempre necessária.
Muitas outras bibliotecas conhecidas, como lodash
, também permitem que os desenvolvedores importem seletivamente diferentes partes dos pacotes. Sem muito trabalho, atualizar as importações de biblioteca em um aplicativo para incluir apenas o que está sendo usado pode resultar em melhorias significativas de desempenho.
Embora o tamanho do pacote tenha sido bastante reduzido, ainda há mais trabalho a fazer. 😈
Remover pacotes desnecessários
Ao contrário do Firebase, importar partes da biblioteca moment
não é tão fácil, mas talvez ela possa ser removida completamente.
O aniversário de cada gatinho fofo é armazenado no formato Unix (milissegundos) no banco de dados do Firebase.
É um carimbo de data/hora de uma data e hora específicas representado pelo número de milissegundos decorridos desde 1º de janeiro de 1970, às 00:00 UTC. Se a data e a hora atuais puderem ser calculadas no mesmo formato, uma pequena função para encontrar a idade de cada gatinho em semanas poderá ser criada.
Como sempre, tente não copiar e colar enquanto acompanha este tutorial. Comece removendo moment
das importações em src/index.js
.
import firebase from 'firebase/app';
import 'firebase/database';
import * as moment from 'moment';
Há um listener de eventos do Firebase que processa mudanças de valor no nosso banco de dados:
favoritesRef.on("value", (snapshot) => { ... })
Acima disso, adicione uma pequena função para calcular o número de semanas a partir de uma data específica:
const ageInWeeks = birthDate => {
const WEEK_IN_MILLISECONDS = 1000 * 60 * 60 * 24 * 7;
const diff = Math.abs((new Date).getTime() - birthDate);
return Math.floor(diff / WEEK_IN_MILLISECONDS);
}
Nessa função, a diferença em milissegundos entre a data e hora atuais (new Date).getTime()
e a data de nascimento (o argumento birthDate
, já em milissegundos) é calculada e dividida pelo número de milissegundos em uma única semana.
Por fim, todas as instâncias de moment
podem ser removidas no listener de eventos usando esta função:
favoritesRef.on("value", (snapshot) => { const { kitties, favorites, names, birthDates } = snapshot.val(); favoritesScores = favorites; kittiesList.innerHTML = kitties.map((kittiePic, index) => {const birthday = moment(birthDates[index]);return ` <li> <img src=${kittiePic} onclick="favKittie(${index})"> <div class="extra"> <div class="details"> <p class="name">${names[index]}</p><p class="age">${moment().diff(birthday, 'weeks')} weeks old</p><p class="age">${ageInWeeks(birthDates[index])} weeks old</p> </div> <p class="score">${favorites[index]} ❤</p> </div> </li> `}) });
Agora, recarregue o aplicativo e confira o painel Rede mais uma vez.
O tamanho do nosso pacote foi reduzido em mais da metade novamente!
Conclusão
Com este codelab, você vai entender bem como analisar um pacote específico e por que é tão útil remover pacotes não usados ou desnecessários. Antes de começar a otimizar um aplicativo com essa técnica, é importante saber que isso pode ser muito mais complexo em aplicativos maiores.
Para remover bibliotecas não usadas, tente descobrir quais partes de um pacote estão sendo usadas e quais não estão. Para um pacote de aparência misteriosa que parece não estar sendo usado em nenhum lugar, verifique quais dependências de nível superior podem precisar dele. Tente encontrar uma maneira de desvincular um do outro.
Quando se trata de remover bibliotecas desnecessárias, as coisas podem ser um pouco mais complicadas. É importante trabalhar em conjunto com sua equipe e verificar se há potencial para simplificar partes da base de código. Remover moment
nesse
aplicativo pode parecer a coisa certa a fazer sempre, mas e se houvesse fusos horários e locais diferentes que precisassem ser processados? Ou
e se houvesse manipulações de data mais complicadas? As coisas podem ficar muito
complicadas ao manipular e analisar datas/horários, e bibliotecas como moment
e date-fns
simplificam isso significativamente.
Tudo é uma troca, e é importante avaliar se vale a pena a complexidade e o esforço para lançar uma solução personalizada em vez de usar uma biblioteca de terceiros.