Minifique e compacte payloads de rede com o gzip

Este codelab mostra como reduzir e compactar o código para o seguinte aplicativo melhora o desempenho da página reduzindo tamanho da solicitação do app.

Captura de tela do aplicativo

Medir

Antes de começar a incluir as otimizações, é sempre uma boa ideia analisar primeiro o estado atual do aplicativo.

  • Para visualizar o site, pressione Ver app. Em seguida, pressione Tela cheia tela cheia

Esse app, que também foi abordado no artigo Remover itens code", permite votar no seu favorito gatinho. 🐈

Agora confira o tamanho do aplicativo:

  1. Pressione "Control+Shift+J" (ou "Command+Option+J" no Mac) para abrir o DevTools.
  2. Clique na guia Rede.
  3. Marque a caixa de seleção Desativar cache.
  4. Atualize o app.

Tamanho original do pacote no painel Rede

Embora muito progresso tenha sido feito na etapa "Remover código não utilizado" codelab para reduzir o tamanho desse pacote. 225 KB ainda é muito grande.

Minificação

Considere o bloco de código a seguir.

function soNice() {
  let counter = 0;

  while (counter < 100) {
    console.log('nice');
    counter++;
  }
}

Se essa função for salva em um arquivo próprio, o tamanho do arquivo será de cerca de 112 bytes (bytes).

Se todos os espaços em branco forem removidos, o código resultante será parecido com este:

function soNice(){let counter=0;while(counter<100){console.log("nice");counter++;}}

O tamanho do arquivo seria de cerca de 83 B. Se ficar ainda mais danificado, reduzindo o comprimento do nome da variável e modificando algumas expressões, o código final pode acabam ficando assim:

function soNice(){for(let i=0;i<100;)console.log("nice"),i++}

O tamanho do arquivo agora atinge 62 B.

A cada etapa, o código fica mais difícil de ler. No entanto, a configuração O mecanismo JavaScript interpreta cada um deles da mesma forma. A benefício de ofuscar o código dessa maneira pode ajudar a obter arquivos menores tamanhos. 112 bilhões não eram muito para começar, mas ainda havia um percentual de 50% redução de tamanho!

Neste aplicativo, a versão 4 do webpack é usada como bundler de módulo. A versão específica pode ser encontrada em package.json.

"devDependencies": {
  //...
  "webpack": "^4.16.4",
  //...
}

A versão 4 já reduz o pacote por padrão durante o modo de produção. Ela usa TerserWebpackPlugin é um plug-in para Terser. Terser é uma ferramenta popular usada para compactar código JavaScript.

Para ter uma ideia da aparência do código minimizado, clique em main.bundle.js enquanto ainda estiver no painel Network do DevTools. Agora clique no guia Resposta.

Resposta reduzida

O código na forma final, minificado e corrompido, é mostrado no corpo da resposta. Para descobrir qual seria o tamanho do pacote se não tiver sido minificado, abra webpack.config.js e atualize a configuração de mode.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

Atualize o aplicativo e confira o tamanho do pacote novamente no Painel Network do DevTools

Tamanho do pacote de 767 KB

É uma grande diferença! 😅

Reverta as mudanças aqui antes de continuar.

module.exports = {
  mode: 'production',
  mode: 'none',
  //...

A inclusão de um processo para reduzir código no seu aplicativo depende das ferramentas que você usa:

  • Se o webpack v4 ou superior for usado, nenhum trabalho adicional precisará ser feito já que o código é minificado por padrão no modo de produção. 👍
  • Se uma versão mais antiga do webpack for usada, instale e inclua TerserWebpackPlugin no processo de compilação do webpack. A documentação explica isso em detalhes.
  • Outros plug-ins de minificação também existem e podem ser usados no lugar deles, como BabelMinifyWebpackPlugin e ClosureCompilerPlugin.
  • Se um bundler de módulo não estiver sendo usado, use Terser. como uma ferramenta da CLI ou incluí-lo diretamente como uma dependência.

Compactação

Embora o termo "compactação" é usado vagamente para explicar como o código é reduzidos durante o processo de minificação, eles não são realmente comprimidos sentido literal.

A compactação geralmente se refere ao código que foi modificado usando uma algoritmo de compactação. Ao contrário da minificação, que acaba fornecendo válido, o código compactado precisa ser descompactado antes de ser usado.

A cada solicitação e resposta HTTP, os navegadores e servidores da Web podem adicionar cabeçalhos para incluir informações adicionais sobre o recurso buscado ou recebido. Isso pode ser na guia Headers do painel "Network do DevTools", em que três tipos são mostrados:

  • General representa cabeçalhos gerais relevantes para toda a solicitação/resposta interação.
  • Cabeçalhos de resposta mostra uma lista de cabeçalhos específicos da resposta real do servidor.
  • Cabeçalhos de solicitação mostra uma lista de cabeçalhos anexados à solicitação pelo para o cliente.

Observe o cabeçalho accept-encoding no Request Headers.

Aceitar cabeçalho de codificação

accept-encoding é usado pelo navegador para especificar qual conteúdo formatos de codificação e de compactação compatíveis. Existem várias algoritmos de compactação de texto, mas existem apenas três que são suportados aqui para a compactação (e descompactação) de solicitações de rede HTTP:

  • Gzip (gzip): a compactação mais usada. para interações entre servidor e cliente. Ele se baseia no Deflate algoritmo conhecido e é compatível com todos os navegadores atuais.
  • Deflate (deflate): não é usado com frequência.
  • Brotli (br): uma compactação mais recente. algoritmo que visa melhorar ainda mais as taxas de compactação, o que pode resultar em carregamentos de página ainda mais rápidos. Ele é suportado no versões mais recentes da maioria dos navegadores.

O aplicativo de exemplo neste tutorial é idêntico ao aplicativo concluído no Codelab "Remover código não utilizado", exceto pelo fato de que O Express agora é usado como um framework de servidor. Nos próximos algumas seções, vamos conhecer a compactação estática e dinâmica.

Compactação dinâmica

A compactação dinâmica envolve a compactação de recursos em tempo real à medida que eles são solicitado pelo navegador.

Prós

  • A criação e a atualização de versões compactadas salvas de recursos não precisam ser feito.
  • A compactação em tempo real funciona especialmente bem para páginas da Web que são geradas de modo dinâmico.

Contras

  • Compactação de arquivos em níveis mais altos para obter taxas de compactação melhores. demora mais. Isso pode causar um impacto na performance enquanto o usuário espera os recursos compactadas antes de serem enviadas pelo servidor.

Compactação dinâmica com o Node/Express

O arquivo server.js é responsável por configurar o servidor do nó que hospeda o aplicativo.

const express = require('express');

const app = express();

app.use(express.static('public'));

const listener = app.listen(process.env.PORT, function() {
  console.log('Your app is listening on port ' + listener.address().port);
});

No momento, tudo o que isso faz é importar express e usar o express.static middleware para carregar todos os arquivos estáticos HTML, JS e CSS na public/ (e esses arquivos são criados pelo webpack em cada build).

Para garantir que todos os recursos sejam compactados sempre que forem solicitados, o compression pode ser usados. Para começar, adicione-o como um devDependency no package.json:

"devDependencies": {
  //...
  "compression": "^1.7.3"
},

E importe-o para o arquivo do servidor, server.js:

const express = require('express');
const compression = require('compression');

E adicione-o como um middleware antes de express.static ser ativado:

//...

const app = express();

app.use(compression());

app.use(express.static('public'));

//...

Agora atualize o app e confira o tamanho do pacote no painel Network.

Tamanho do pacote com compactação dinâmica

De 225 KB a 61,6 KB! No Response Headers agora, um content-encoding mostra que o servidor está enviando esse arquivo codificado com gzip.

Cabeçalho de codificação de conteúdo

Compactação estática

A ideia por trás da compactação estática é ter os recursos compactados e salvos com antecedência.

Prós

  • A latência devido aos altos níveis de compactação não é mais uma preocupação. Nada precisa acontecer imediatamente para compactar arquivos, pois agora eles podem ser obtidos diretamente.

Contras

  • Os recursos precisam ser compactados em cada build. Os tempos de build podem aumentar significativamente se altos níveis de compactação forem usados.

Compactação estática com o Node/Express e o webpack

Como a compactação estática envolve a compactação de arquivos antecipadamente, o webpack podem ser modificadas para compactar recursos como parte da etapa de criação. CompressionPlugin pode ser usada para isso.

Para começar, adicione-o como um devDependency no package.json:

"devDependencies": {
  //...
  "compression-webpack-plugin": "^1.1.11"
},

Como qualquer outro plug-in do webpack, importe-o no arquivo de configurações, webpack.config.js:

const path = require("path");

//...

const CompressionPlugin = require("compression-webpack-plugin");

E inclua-o na matriz plugins:

module.exports = {
  //...
  plugins: [
    //...
    new CompressionPlugin()
  ]
}

Por padrão, o plug-in compacta os arquivos de build usando gzip. Dê uma olhada na documentação para saber como adicionar opções para usar um algoritmo diferente ou incluir/excluir determinados arquivos.

Quando o aplicativo é recarregado e criado novamente, uma versão compactada do pacote principal é foi criado. Abra o Glitch Console para ver o que tem dentro do public/ final exibido pelo servidor do nó.

  • Clique no botão Ferramentas.
  • Clique no botão Console.
  • No console, execute os comandos a seguir para mudar para public e confira todos os seus arquivos:
cd public
ls

Arquivos finais gerados no diretório público

A versão compactada em gzip do pacote, main.bundle.js.gz, agora está salva aqui como muito bem. CompressionPlugin também compacta index.html por padrão.

A próxima etapa é pedir para o servidor enviar esses arquivos sempre que suas versões JS originais forem solicitadas. Isso pode ser feito definindo uma nova rota em server.js antes que os arquivos sejam disponibilizados com express.static.

const express = require('express');
const app = express();

app.get('*.js', (req, res, next) => {
  req.url = req.url + '.gz';
  res.set('Content-Encoding', 'gzip');
  next();
});

app.use(express.static('public'));

//...

app.get é usada para informar ao servidor como responder a uma solicitação GET para um em um endpoint específico. Uma função de callback é usada para definir como lidar com o solicitação. O trajeto funciona assim:

  • Especificar '*.js' como o primeiro argumento significa que ele funciona para cada que é disparado para buscar um arquivo JS.
  • No callback, .gz é anexado ao URL da solicitação e ao O cabeçalho de resposta Content-Encoding está definido como gzip.
  • Por fim, next() garante que a sequência continue para qualquer callback que podem vir a seguir.

Quando o app for atualizado, confira o painel Network mais uma vez.

Redução do tamanho do pacote com compactação estática

Assim como antes, uma redução significativa no tamanho dos pacotes.

Conclusão

Este codelab abordou o processo de minificação e compactação do código-fonte. Ambas as técnicas estão se tornando padrão em muitas das ferramentas por isso, é importante descobrir se o conjunto de ferramentas já ou se você deve começar a aplicar os dois processos por conta própria.