Este codelab é uma extensão do codelab Reduzir e compactar payloads de rede
(em inglês) e pressupõe que você esteja familiarizado com os conceitos básicos de compactação. Em
comparação com outros algoritmos de compactação, como gzip
, este codelab explica como
a compactação Brotli pode reduzir ainda mais as taxas de compactação e o tamanho geral
do app.
Medida
Antes de começar a adicionar otimizações, é sempre bom analisar o estado atual do aplicativo.
- Clique em Remixar para editar para tornar o projeto editável.
- Para visualizar o site, pressione View App. Em seguida, pressione Fullscreen .
No codelab anterior Minificar e compactar payloads
de rede,
reduzimos o tamanho do main.js
de 225 KB para 61,6 KB. Neste codelab, você
aprenderá como a compactação Brotli pode reduzir ainda mais o tamanho desse pacote.
Compressão Brotli
O Brotli
é um algoritmo de compactação mais recente que pode fornecer resultados de compactação
de texto ainda melhores do que o gzip
. De acordo com a
CertSimple, a performance de Brotli é:
- 14% menor que
gzip
para JavaScript - 21% menor que
gzip
para HTML - 17% menor que
gzip
no CSS
Para usar o Brotli, seu servidor precisa ser compatível com HTTPS. O Brotli é compatível com as
versões mais recentes da maioria dos navegadores (link em inglês). Navegadores
compatíveis com o Brotli incluirão br
em cabeçalhos Accept-Encoding
:
Accept-Encoding: gzip, deflate, br
É possível determinar qual algoritmo de compactação é usado no campo Content-Encoding
na guia "Rede" das Ferramentas para desenvolvedores do Chrome (Command+Option+I
ou
Ctrl+Alt+I
):
Como ativar o Brotli
Compactação dinâmica
A compactação dinâmica envolve a compactação de recursos em tempo real à medida que eles são solicitados pelo navegador.
Prós
- A criação e a atualização de versões compactadas salvas de recursos não precisam ser feitas.
- A compactação funciona especialmente bem para páginas da Web geradas dinamicamente.
Contras
- A compactação de arquivos em níveis mais altos para alcançar taxas de compactação melhores leva mais tempo. Isso pode causar um impacto de desempenho, já que o usuário espera a compactação dos recursos antes de serem enviados 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.
var express = require('express');
var app = express();
app.use(express.static('public'));
var listener = app.listen(process.env.PORT, function() {
console.log('Your app is listening on port ' + listener.address().port);
});
Atualmente, tudo isso faz é importar express
e usar o middleware express.static
para carregar todos os arquivos estáticos HTML, JS e CSS na
public/directory
(e esses arquivos são criados pelo webpack em cada build).
Para garantir que todos os recursos sejam compactados usando brotli sempre que forem
solicitados, o módulo
shrink-ray
pode ser usado. Para começar, adicione-o como um devDependency
no package.json
:
"devDependencies": {
//...
"shrink-ray": "^0.1.3"
},
E importe-o para o arquivo do servidor, server.js
:
var express = require('express');
var shrinkRay = require('shrink-ray');
E adicione-o como um middleware antes de express.static
ser ativado:
//...
var app = express();
// compress all requests
app.use(shrinkRay());
app.use(express.static('public'));
Agora, atualize o app e confira o tamanho do pacote no painel "Network":
Agora é possível conferir que a brotli
é aplicada de bz
no cabeçalho Content-Encoding
.
main.bundle.js
foi reduzido de 225 KB para 53,1 KB. Isso é cerca de 14% menor
em comparação com gzip
(61,6 KB).
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 instantaneamente para compactar arquivos, porque agora eles podem ser buscados 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 antecipada de arquivos, as configurações
do webpack podem ser modificadas para compactar recursos como parte da etapa de build. O
brotli-webpack-plugin
pode ser usado para isso.
Para começar, adicione-o como um devDependency
no package.json
:
"devDependencies": {
//...
"brotli-webpack-plugin": "^1.1.0"
},
Como qualquer outro plug-in do webpack, importe-o no arquivo de configurações,
webpack.config.js
:
var path = require("path");
//...
var BrotliPlugin = require('brotli-webpack-plugin');
Inclua-o na matriz de plug-ins:
module.exports = {
// ...
plugins: [
// ...
new BrotliPlugin({
asset: '[file].br',
test: /\.(js)$/
})
]
},
A matriz do plug-in usa os seguintes argumentos:
asset
: o nome do recurso de destino.[file]
foi substituído pelo nome do arquivo do recurso original.test
: todos os recursos que correspondem a essa RegExp (ou seja, recursos JavaScript que terminam em.js
) são processados.
Por exemplo, main.js
seria renomeado como main.js.br
.
Quando o app é recarregado e criado, uma versão compactada do pacote principal é
criada. Abra o Glitch Console para conferir o que está dentro do diretório
public/
final que é disponibilizado pelo servidor do nó.
- Clique no botão Ferramentas.
- Clique no botão Console.
- No console, execute os seguintes comandos para mudar para o diretório
public
e ver todos os arquivos:
cd public
ls -lh
A versão compactada brotli do pacote, main.bundle.js.br
, agora também está salva aqui e tem aproximadamente 76% de tamanho menor (225 KB versus 53 KB) do que main.bundle.js
.
Em seguida, peça para o servidor enviar esses arquivos compactados sempre que as versões originais do JS forem solicitadas. Isso pode ser feito definindo uma nova
rota em server.js
antes que os arquivos sejam disponibilizados com express.static
.
var express = require('express');
var app = express();
app.get('*.js', (req, res, next) => {
req.url = req.url + '.br';
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
next();
});
app.use(express.static('public'));
app.get
é usado para informar ao servidor como responder a uma solicitação GET
para um endpoint específico. Uma função de callback é usada para definir como processar a
solicitação. O trajeto funciona assim:
- Especificar
'*.js'
como o primeiro argumento significa que isso funciona para cada endpoint acionado para buscar um arquivo JS. - No callback,
.br
é anexado ao URL da solicitação, e o cabeçalho de respostaContent-Encoding
é definido comobr
. - O cabeçalho
Content-Type
é definido comoapplication/javascript; charset=UTF-8
para especificar o tipo MIME. - Por fim,
next()
garante que a sequência continue em qualquer callback que possa ser a seguir.
Como alguns navegadores podem não ser compatíveis com a compactação brotli, confirme se ela é compatível antes de retornar o arquivo compactado brotli verificando se o cabeçalho da solicitação Accept-Encoding
inclui br
:
var express = require('express');
var app = express();
app.get('*.js', (req, res, next) => {
if (req.header('Accept-Encoding').includes('br')) {
req.url = req.url + '.br';
console.log(req.header('Accept-Encoding'));
res.set('Content-Encoding', 'br');
res.set('Content-Type', 'application/javascript; charset=UTF-8');
}
next();
});
app.use(express.static('public'));
Quando o app recarregar, confira o painel Network mais uma vez.
Pronto. Você usou a compactação Brotli para compactar ainda mais seus recursos.
Conclusão
Este codelab ilustrou como o brotli
pode reduzir ainda mais o tamanho geral
do app. Quando compatível, brotli
é um algoritmo de compactação mais eficiente que
gzip
.