Reduzir payloads de JavaScript com a divisão de código

A maioria das páginas da Web e dos aplicativos é composta de muitas partes diferentes. Em vez de enviar todo o JavaScript que compõe o aplicativo assim que a primeira página é carregada, dividir o JavaScript em vários fragmentos melhora a performance da página.

Este codelab mostra como usar a divisão de código para melhorar o desempenho de um aplicativo simples que classifica três números.

Uma janela do navegador mostra um aplicativo chamado "Magic Sorter" com três campos para inserir números e um botão "Classificar".

Medida

Como sempre, é importante avaliar a performance de um site antes de tentar adicionar otimizações.

  1. Para visualizar o site, pressione Ver app. Em seguida, pressione Tela cheia modo tela cheia.
  2. Pressione "Control + Shift + J" (ou "Command + Option + J" no Mac) para abrir o DevTools.
  3. Clique na guia Rede.
  4. Marque a caixa de seleção Desativar cache.
  5. Atualize o app.

Painel "Network" mostrando o pacote JavaScript de 71,2 KB.

71,2 KB de JavaScript, só para classificar alguns números em um aplicativo simples. What gives?

No código-fonte (src/index.js), a biblioteca lodash é importada e usada nesse aplicativo. O Lodash oferece muitas funções utilitárias úteis, mas apenas um método do pacote está sendo usado aqui. Instalar e importar dependências de terceiros inteiras em que apenas uma pequena parte delas está sendo usada é um erro comum.

Otimizar

Existem algumas maneiras de reduzir o tamanho do pacote:

  1. Crie um método de classificação personalizado em vez de importar uma biblioteca de terceiros
  2. Usar o método Array.prototype.sort() integrado para classificar numericamente
  3. Importe o método sortBy apenas de lodash, não de toda a biblioteca.
  4. Fazer o download do código para classificação somente quando o usuário clicar no botão

As opções 1 e 2 são métodos perfeitamente apropriados para reduzir o tamanho do pacote e provavelmente fariam mais sentido para um aplicativo real. No entanto, eles não são usados neste tutorial apenas para o ensino RULE.

As opções 3 e 4 ajudam a melhorar o desempenho desse aplicativo. As próximas seções deste codelab abrangem essas etapas. Como qualquer tutorial de programação, sempre tente escrever o código por conta própria em vez de copiar e colar.

Importe apenas o que precisa

Alguns arquivos precisam ser modificados para importar apenas o único método de lodash. Para começar, substitua esta dependência em package.json:

"lodash": "^4.7.0",

por:

"lodash.sortby": "^4.7.0",

Agora, em src/index.js, importe este módulo específico:

import "./style.css";
import _ from "lodash";
import sortBy from "lodash.sortby";

E atualize como os valores são classificados:

form.addEventListener("submit", e => {
  e.preventDefault();
  const values = [input1.valueAsNumber, input2.valueAsNumber, input3.valueAsNumber];
  const sortedValues = _.sortBy(values);
  const sortedValues = sortBy(values);

  results.innerHTML = `
    <h2>
      ${sortedValues}
    </h2>
  `
});

Atualize o aplicativo, abra o DevTools e confira o painel Network mais uma vez.

Painel &quot;Network&quot; mostrando o pacote JavaScript de 15,2 KB.

Para este aplicativo, o tamanho do pacote foi reduzido em mais de quatro vezes com muito pouco trabalho, mas ainda há espaço para melhorias.

Divisão de código

O webpack é um dos bundlers de módulos de código aberto mais usados atualmente. Em resumo, agrupa todos os módulos JavaScript, assim como outros recursos, que compõem um aplicativo da Web em arquivos estáticos que podem ser lidos pelo navegador.

O único pacote usado neste aplicativo pode ser dividido em dois blocos separados:

  • Um responsável pelo código que compõe nossa rota inicial
  • Um bloco secundário que contém nosso código de classificação

Com o uso de importações dinâmicas, um bloco secundário pode ser carregado lentamente ou carregado sob demanda. Neste aplicativo, o código que compõe o bloco só pode ser carregado quando o usuário pressiona o botão.

Comece removendo a importação de nível superior do método de classificação em src/index.js:

import sortBy from "lodash.sortby";

Importe-a dentro do listener de eventos que dispara quando o botão é pressionado:

form.addEventListener("submit", e => {
  e.preventDefault();
  import('lodash.sortby')
    .then(module => module.default)
    .then(sortInput())
    .catch(err => { alert(err) });
});

O recurso import() faz parte de uma proposta (atualmente na fase 3 do processo TC39) para incluir a capacidade de importar dinamicamente um módulo. O webpack já inclui suporte para isso e segue a mesma sintaxe estabelecida pela proposta.

import() retorna uma promessa e, quando ela é resolvida, o módulo selecionado é fornecido e é dividido em um bloco separado. Depois que o módulo for retornado, module.default será usado para fazer referência à exportação padrão fornecida pelo lodash. A promessa é encadeada com outro .then que chama um método sortInput para classificar os três valores de entrada. No final da cadeia de promessas,catch() é usado para processar casos em que a promessa é rejeitada devido a um erro.

A última coisa que precisa ser feita é gravar o método sortInput no final do arquivo. Precisa ser uma função que retorne uma função que use o método importado de lodash.sortBy. A função aninhada pode classificar os três valores de entrada e atualizar o DOM.

const sortInput = () => {
  return (sortBy) => {
    const values = [
      input1.valueAsNumber,
      input2.valueAsNumber,
      input3.valueAsNumber
    ];
    const sortedValues = sortBy(values);

    results.innerHTML = `
      <h2>
        ${sortedValues}
      </h2>
    `
  };
}

Monitoramento

Atualize o aplicativo uma última vez e fique de olho no painel Rede novamente. Apenas um pequeno pacote inicial é transferido por download assim que o app é carregado.

Painel &quot;Network&quot; mostrando o pacote JavaScript de 2,7 KB.

Depois que o botão é pressionado para classificar os números de entrada, o bloco que contém o código de classificação é buscado e executado.

Painel de rede mostrando o pacote JavaScript de 2,7 KB seguido por um pacote de JavaScript de 13,9 KB.

Observe como os números ainda são classificados.

Conclusão

A divisão de código e o carregamento lento podem ser técnicas extremamente úteis para reduzir o tamanho do pacote inicial do seu aplicativo, e isso pode resultar diretamente em tempos de carregamento de página muito mais rápidos. No entanto, há algumas coisas importantes que precisam ser consideradas antes de incluir essa otimização no seu aplicativo.

interface de carregamento lento

Ao fazer o carregamento lento de módulos de código específicos, é importante considerar como a experiência seria para usuários com conexões de rede mais fracas. Dividir e carregar um bloco muito grande de código quando um usuário envia uma ação pode fazer parecer que o aplicativo parou de funcionar. Por isso, considere mostrar um indicador de carregamento de algum tipo.

Carregamento lento de módulos de nó de terceiros

Nem sempre essa é a melhor abordagem para o carregamento lento de dependências de terceiros no aplicativo, e isso depende de onde você as usa. Normalmente, as dependências de terceiros são divididas em um pacote vendor separado que pode ser armazenado em cache, já que não é atualizado com tanta frequência. Leia mais sobre como o SplitChunksPlugin pode ajudar você a fazer isso.

Carregamento lento com framework JavaScript

Muitos frameworks e bibliotecas conhecidos que usam webpack fornecem abstrações para facilitar o carregamento lento do que usar importações dinâmicas no meio do aplicativo.

Embora seja útil entender como as importações dinâmicas funcionam, sempre use o método recomendado pela biblioteca/biblioteca para fazer o carregamento lento de módulos específicos.

Pré-carregamento e pré-busca

Sempre que possível, aproveite as dicas do navegador, como <link rel="preload"> ou <link rel="prefetch">, para tentar carregar módulos críticos ainda mais cedo. O webpack é compatível com as duas dicas usando comentários mágicos em instruções de importação. Isso é explicado com mais detalhes no guia Pré-carregar blocos críticos.

Carregamento lento além do código

As imagens podem compor uma parte significativa de um aplicativo. O carregamento lento daqueles que estão abaixo da dobra ou fora da janela de visualização do dispositivo pode acelerar um site. Leia mais sobre isso no guia Lazysizes.