Minificação de arquivos para Web

Artigo que explica sobre a minificação de arquivos para serem trafegados via HTTP na web.

Introdução
compressão de arquivos

O ambiente web é repleto de requisições e respostas HTTP contendo arquivos HTML, JS, CSS, imagens, etc. Dependendo da arquitetura da aplicação, cada página pode requerer muitos arquivos de estilos, script ou imagens auxiliares, que acabam consumindo tempo para serem baixados e processados pelo navegador. Portanto, é útil aplicar algumas técnicas para minimizar o tamanho destes arquivos, afinal, arquivos menores podem ser trafegados mais rapidamente. Uma página rápida é sempre bem vista pelos buscadores, como o Google, pois impacta diretamente numa melhor experiência do usuário.

Neste artigo, veremos algumas dicas de como minimizar o tamanho de alguns tipos de arquivos, para tornar as páginas mais rápidas de serem carregadas e, consequentemente, ter maior relevância para buscadores. Os assuntos estão divididos em:

Minificando arquivos JS e CSS

Todos que trabalham com JavaScript e CSS sabem que a sintaxe destas linguagens permitem a utilização de indentação, quebras de linha e espaços, que são muito úteis para a legibilidade. No entanto, a maioria destas indentações, quebras de linha e espaços não tem nenhum efeito sobre o resultado gerado por estes arquivos, portanto, são dispensáveis.

O processo de minificação de arquivos, portanto, tem o objetivo de remover caracteres dispensáveis de forma que o arquivo final tenha um tamanho menor que o arquivo original, mas o mesmo resultado.

No caso do JavaScript, ainda existem outras possíveis otimizações, como a substituição de nomes grandes de variáveis ou funções por nomes mais curtos. Além disso, o processo pode ser acompanhado de um "embaralhamento" do código, que tem o objetivo de ofuscar o funcionamento do código, mas sem interferir em seu resultado principal.

Existem vários minificadores e ofuscadores no mercado, mas vou apresentar a seguir uma ferramenta que faz estas tarefas muito bem: o YUI-compressor.

O programa é em java, então você precisa de uma máquina virtual java (JVM) instalada para executá-lo. Com tudo pronto, acesse o link para baixar o YUI-compressor, baixe o "JAR" em algum diretório.

Para executá-lo, é muito simples. Veja como minificar um arquivo CSS chamado "arquivo.css" e gerar o arquivo minificado em "arquivo.min.css":

$ java -jar /caminho/do/yuicompressor-2.4.8.jar --type css -o arquivo.min.css arquivo.css

Naturalmente que na sua aplicação será necessário ajustar a inclusão do CSS (pela tag <link>), para que seja incluído o arquivo minificado.

Para minificar um arquivo JS chamado "arquivo.js" e gerar o arquivo minificado e ofuscado em "arquivo.min.js":

$ java -jar /caminho/do/yuicompressor-2.4.8.jar --type js -o arquivo.min.js arquivo.js

De forma análoga, você vai precisar ajustar a inclusão do JS (pela tag <script>), para que seja incluído o arquivo minificado.

Alguns parâmetros extras que você pode passar são:

  • --charset [charset] Para informar a codificação do arquivo.
  • --line-break [tamanho] Para aplicar uma quebra de linha após [tamanho] caracteres, ou passe "0" (zero) para aplicar uma quebra de linha após cada ponto e vírgula.
  • --nomunge Para não ofuscar o JavaScript, apenas minificar.
  • --preserve-semi Para manter todas os ponto e vírgulas do JavaScript.
  • --disable-optimizations Para não aplicar micro-otimizações no JavaScript.

Apresentado o funcionamento do YUI-compressor, você fica livre para definir onde serão colocados os arquivos minificados. Você pode fazer um script que minifica todos arquivos CSS e JS, mantendo as versões minificadas no mesmo diretório em que os arquivos originais estavam, mas também pode separá-los em duas pastas diferentes (uma onde ficarão os arquivos originais e outra para os arquivos minificados).

Otimizando arquivos PNG

Arquivos de imagens PNG também podem ser otimizados para que tenham um tamanho em bytes menor, mas mantendo a imagem praticamente idêntica (inclusive suas dimensões). Para isso, você pode usar um programa do Linux chamado optipng. Existem vários parâmetros que você pode usar no processo de otimização, mas talvez o mais relevante seja o parâmetro -o, que especifica o nível de otimização (1 é o mais baixo e 9 é o mais alto).

Veja um exemplo de como otimizar um arquivo "logo.png" com o nível máximo de otimização (após executá-lo, será mostrado o percentual de redução do tamanho do arquivo em relação ao original):

$ optipng -o 9 logo.png

Usando o comando da forma mostrada, o arquivo logo.png será sobrescrito com a sua versão mais otimizada. Mas se você preferir gerar o arquivo otimizado com outro nome, basta chamá-lo com o parâmetro -out seguido do nome de arquivo desejado:

$ optipng -o 9 logo.png -out logo.min.png

Outra forma é passar o parâmetro -keep ou -backup, para fazer um backup do arquivo original (com o nome do arquivo original seguido de ".bak") e substituindo o arquivo original com a versão otimizada:

$ optipng -o 9 logo.png -keep

Observações: o nível de otimização 9 é o mais lento, embora seja o mais eficiente em reduzir o tamanho do arquivo. Caso esteja trabalhando com um arquivo PNG com dimensões muito grandes e ele seja otimizado com nível 9, pode ser que ele demore um pouquinho mais para que o navegador consiga exibí-lo. Ou seja, ele passa a ser trafegado pela rede mais rapidamente (por ter um tamanho menor), mas é mais lento para ser interpretado pelo navegador. Portanto, vale a pena fazer alguns experimentos, especialmente nestes casos de arquivos de dimensões muito grantes. Afinal, nem sempre a redução de tamanho justifica aplicar uma compressão muito alta.

Otimizando arquivos JPG

No caso de arquivos JPG, também existe um programa no Linux chamado jpegoptim. Ele funciona de forma similar ao optipng, mas tem outros parâmetros.

Existem duas formas básicas de se utilizar este comando. A primeira, você especifica a qualidade final da imagem, numa escala de 0 a 100, através do parâmetro -m ou --max=. Quanto menor a qualidade, menor tende a ser o tamanho do arquivo, porém, as cores da imagem ficam mais distorcidas também. Ou seja, para usar a otimização desta forma, é importante verificar como está ficando o resultado final, para que o aspecto das cores seja afetado o mínimo quanto possível e que a mudança seja quase imperceptível a olho nú. Normalmente utilizo uma qualidade entre 80 a 90. Geralmente há uma redução considerável de tamanho do arquivo, e quase não dá pra notar distorções na imagem. Mas essa faixa pode variar de imagem pra imagem.

Veja um exemplo de otimização de uma imagem "paisagem.jpg" para que fique com qualidade 85:

$ jpegoptim -m85 paisagem.jpg

A segunda forma de otimizar a imagem é informando o tamanho final desejado para o arquivo através do parâmetro -S ou --size=, que pode ser em kB ou em percentual. Por exemplo, temos uma imagem de 13kB e queremos que o programa a otimize para que tenha 6kB. Neste caso, executamos desta forma:

$ jpegoptim -S6 paisagem.jpg

Note que o programa vai tentar fazer a melhor otimização possível, mas manter o arquivo com mais de 6kB. Quanto mais otimizações o programa precisar fazer para chegar ao tamanho esperado, mais distorcidas ficam as cores da imagem. Portanto, é uma forma útil de se chamar o programa quando você realmente espera que o tamanho do arquivo não seja muito superior a um determinado valor.

Para reduzir o tamanho do arquivo com base em um percentual, basta usar especificar o valor seguido de "%". Por exemplo, se queremos reduzir o tamanho de uma imagem para pelo menos 80% de seu tamanho original, fazemos assim:

$ jpegoptim -S80% paisagem.jpg

Os exemplos apresentados até aqui do jpegoptim fazem com que o arquivo seja sobrescrito. Para que você consiga gerar o arquivo otimizado com outro nome, você pode fazer desta forma:

$ jpegoptim -m85 -f --stdout paisagem.jpg > paisagem.min.jpg

Minificação de arquivos HTML

A minificação de arquivos HTML envolve basicamente a remoção de espaços e quebras de linha desnecessários. O problema, no entanto, é que existem algumas tags em que a quantidade de espaços e quebras de linha inseridos dentro delas afetam o layout do elemento. Por exemplo, a tag <pre>. Porém, isso não é exclusividade desta tag, pois qualquer elemento que possua estilo CSS cuja propriedade white-space tenha valor pre, pre-line ou pre-wrap também serão afetados pela quantidade de espaços e quebras de linha.

Não conheço um programa que faça a minificação de arquivos HTML, mas você pode fazê-lo com uma expressão regular simples como essa (lembrando que ela vai remover espaços e quebras de linha, mesmo de elementos como o <pre>):

$html = preg_replace('/(\s)\s+/m', '$1', $html);

Portanto, se você trabalha com MVC (ou pelo menos separa a camada de visualização da camada de lógica da aplicação), então pode aplicar essa expressão regular para transformar o conteúdo de uma string que tem um HTML em uma versão minificada.

A expressão regular que mostrei mantém as quebras de linha do arquivo (desde que o caractere anterior à quebra de linha seja um espaço ou outra quebra de linha). Porém, em muitos casos, a quebra de linha também não afeta o layout. Por exemplo, os dois códigos HTML abaixo produzem o mesmo resultado visual:

<p>Primeiro parágrafo</p>
<p>Segundo parágrafo</p>
<p>Primeiro parágrafo</p><p>Segundo parágrafo</p>

Isso acontece porque a tag <p> (parágrafo) é um elemento de bloco (display=block). Porém, esta regra não vale para elementos inline (como as tags <a>, <strong>, <em>, <b>, <i>, <span>, etc). Portanto, os códigos abaixo NÃO produzem o mesmo resultado visual:

<strong>Oi</strong>
<strong>Olá</strong>
<strong>Oi</strong><strong>Olá</strong>

No primeiro exemplo será exibido "Oi Olá" com um espaço entre eles. No segundo exemplo será exibido "OiOlá" sem nenhum espaço entre eles. Portanto, é preciso cautela para remover as quebras de linha.

A princípio, podemos rodar essa outra instrução para remover todos os espaços do documento:

$html = strtr($html, array("\r" => '', "\n" => ''));

Porém, você vai precisar colocar um espaço forçado antes da quebra de linha quando houver um elemento inline seguido de uma quebra de linha seguido de outro elemento inline, como neste exemplo:

    <strong>Oi</strong>&nbsp;
    <strong>Olá</strong>

Ao aplicar as duas expressões regulares sobre essa string, será gerado o seguinte resultado:

<strong>Oi</strong>&nbsp;<strong>Olá</strong>

Você pode adotar a mesma solução para prevenir que espaços e quebras de linha sejam eliminados de elementos como a tag <pre>. Ou seja, colocar &nbsp; onde quiser forçar a existência de um espaço e &#10; para forçar a existência de uma quebra de linha. Seguindo estas precauções, pode usar o código abaixo com segurança para minificar o HTML mantendo o mesmo resultado visual:

$html = strtr(preg_replace('/(\s)\s+/m', '$1', $html), array("\r" => '', "\n" => ''));

2 comentários

Anônimo disse...

Boa Rubens!!! Eh nois!!!

Otimo post! Deu uma luz na minificação!

Layo