Tornar um site mais rápido com compressão Gzip e Brotli

Está na hora de actualizar um dos artigos mais lidos do blog sobre compressão, com novas ferramentas que se encontram agora disponíveis.

Quer tornar o seu site ainda mais rápido em Desktop e Mobile e melhorar o resultado do PageSpeed? Vamos a isso!

Funcionário empurra pessoas no comboio em Tóquio

Este artigo não se aplica a todos os developers, e o ideal será ter um pré-processador como o Gulp para automatizar estes processos de forma a aumentar a sua produtividade.

Irei basear-me na configuração de um servidor com Apache (CPanel) e no pré-processador Gulp.

Conteúdo estático CSS e JS

A maioria dos tutoriais na net vão indicar que se deve fazer a compressão destes ficheiros em tempo real pelo servidor. Essa é a forma mais fácil de o fazer mas trás várias desvantagens: aumento de carga, consumo de memória e tempo de compressão que pode ser contraproducente e demorar mais do que servir o elemento sem compressão, dependendo do servidor e tipo de compressão.

Com a utilização de pré-processadores para minificar CSS e JS, passar SASS para CSS e afins podemos adicionar mais 1 ou 2 passos e ter a melhor compressão possível sem carga alguma no servidor.

Vamos usar Gzip com o algoritmo Zopfli, desenvolvido pela Google, e um novo formato Brotli também desenvolvido pela Google especificamente para a web.

O primeiro passo é configurar o nosso servidor para enviar a codificação certa com a extensão com compressão e adicionar alguns headers para compatibilidade com proxys.

Este código pode ser adicionado a um ficheiro .htaccess ou semelhante, ou adicionado a nível geral no servidor. No caso de um servidor CPanel pode ser adicionado ao ficheiro post_virtualhost_global.conf em Apache Configuration > Include Editor.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# Ficheiros com compressão Brotli
<Files *.js.br>
    AddType "text/javascript" .br
    AddEncoding br .br
</Files>
<Files *.css.br>
    AddType "text/css" .br
    AddEncoding br .br
</Files>

# Ficheiros com compressão Gzip
<Files *.js.gz>
    AddType "text/javascript" .gz
    AddEncoding gzip .gz
</Files>
<Files *.css.gz>
    AddType "text/css" .gz
    AddEncoding gzip .gz
</Files>

# Headers para proxys
<Files *.br>
	Header set Content-Encoding: br
	Header set Vary: Accept-Encoding
</Files>
<Files *.gz>
	Header set Content-Encoding: gzip
	Header set Vary: Accept-Encoding
</Files>

Depois associado a cada domínio / vhost também num ficheiro .htaccess ou semelhante adicionamos uma regra para devolver o ficheiro em Brotli ou Gzip conforme o que for suportado pelo browser do utilizador.

1
2
3
4
5
6
7
8
9
10
11
12
# Necessário caso ainda não tenha sido iniciado anteriormente
RewriteEngine On

# Fornece ficheiro pré-comprimido em Brotli
RewriteCond %{HTTP:Accept-Encoding} br
RewriteCond %{REQUEST_FILENAME}.br -f
RewriteRule ^(.*)$ $1.br [L]

# Fornece ficheiro pré-comprimido em Gzip
RewriteCond %{HTTP:Accept-Encoding} gzip
RewriteCond %{REQUEST_FILENAME}.gz -f
RewriteRule ^(.*)$ $1.gz [L]

A configuração está feita, e agora como gerar os ficheiros? No artigo antigo sugeri usar o 7-Zip para criar os Gzip, mas agora existem ferramentas melhores. Se não usam um pré-processador podem usar o 7-Zip, assim como usar esta ferramenta para a compressão em Brotli, mas vão ter mais trabalho

Gerar ficheiros estáticos através do Gulp

Como uso Gulp para várias tarefas como passar SASS para CSS, minify e cache busting de CSS, JS e SVG faz todo o sentido adicionar estas tarefas de compressão ao meu processo que corro antes de enviar os ficheiros para produção.

Com a integração com o PHPStorm com dois cliques em menos de 500ms tenho tudo pronto a enviar, ficheiros Gzip e Brotli incluídos.

Se não usam um pré-processador como o Gulp não sabem o que estão a perder.

Vamos precisar de dois módulos: gulp-zopfli e gulp-brotli. Podem ser facilmente instalados com estes dois comandos:

1
2
npm install gulp-zopfli --save-dev
npm install gulp-brotli --save-dev

Adiciona-se os require ao gulpfile.js

1
2
var zopfli = require('gulp-zopfli');
var brotli = require('gulp-brotli');

De seguida criamos duas novas tarefas, uma para a compressão Gzip com o algoritmo Zopfli e outra para Brotli. Para simplificar apenas adicionei como exemplo ficheiros CSS e JS mas pode ser aplicado a outras extensões como SVG. O mesmo para o caminho, estão aqui hardcoded para ser mais fácil a sua compreensão.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Compressão Gzip
gulp.task('zopfli', function(){
    return gulp.src('dist/*.{js,css}')
        .pipe(zopfli({ format: 'gzip' }))
        .pipe(gulp.dest('dist/'));
});

// Compressão Brotli
gulp.task('brotli', function(){
    return gulp.src('dist/*.{js,css}')
        .pipe(brotli.compress({
            extension: 'br',
            quality: 11
        }))
        .pipe(gulp.dest('dist/'));
});

E agora é uma simples questão de adicionar estas novas tarefas à tarefa existente que corro antes de enviar ficheiros estáticos para o servidor em produção.

1
2
3
4
5
gulp.task('build', gulp.series(
    'clean',
    gulp.parallel('styles', 'scripts'),
    gulp.parallel('zopfli', 'brotli')
));

Já usava o método antigo, vale a pena mudar?

O método antigo já é uma boa optimização. A compressão em Gzip com o 7-Zip já permitiam reduções superiores a 60% e se a diferença entre 7-Zip e Gzip com Zopfli é de apenas 1%, com Brotli temos uma diferença de 6%.

Aqui fica uma tabela com os resultados de um teste que efectuei num ficheiro Javascript.

MinifyGzip (7-Zip)Gzip (Zopfli)Brotli
Tamanho5,99 KB2,37 KB2,33 KB1,94 KB

Vale a pena mudar se for usado um pré-processador, ai apenas se gastam 30 minutos a adicionar estas configurações ao servidor e a adicionar duas novas tarefas ao processo já existente. No caso do Brotli as diferenças fazem especial sentido em mobile e já existe suporte em Android e browsers como o Chrome e Firefox. Até o Edge em Desktop suporta!

Conteúdo dinâmico

Usar Zopfli e Brotli em conteúdo dinâmico não faz sentido. O ponto forte destes novos algoritmos é que apesar de demorarem mais tempo no processo de compressão têm tempos de descompressão muito semelhantes ao Gzip normal. E é por isso que apenas devem ser usados em ficheiros estáticos, pré-comprimidos antes de os enviar para o servidor.

No caso de conteúdo dinâmico (páginas vindas de PHP, chamadas AJAX, etc) devemos continuar a usar o mod_deflate do Apache.

1
2
3
<IfModule mod_deflate.c>
  AddOutPutFilterByType DEFLATE text/html application/json
</IfModule>

Também pode ser adicionado conteúdo estático ao mod_deflate para simplificar as coisas em ambientes onde não existem pré-processadores ou que existem ficheiros CSS e JS gerados dinamicamente através de um CMS por exemplo.

Como testar se funcionou?

A ferramenta de Compressão HTTP foi actualizada para verificar não só a compressão com Gzip e Deflate mas também Brotli. Basta colocar o endereço do ficheiro CSS, JS ou outro e confirmar se a compressão funciona em Gzip e Brotli.

 
Copyright © 1985 - 2017 Eduardo Maio. Alguns direitos reservados.
eduardomaio.net - Às vezes mais valia ser Agricultor do que Programador
Ao navegar no blog eduardomaio.net está a concordar com os termos legais e de privacidade.