Oi Sou Vanya, líder da equipe de plataforma da Tinkoff Business.
Meu passatempo favorito é abrir a guia DevTools e verificar a quantidade de artefatos do site. Neste artigo, mostrarei como reduzimos o peso do aplicativo em 30% com a ajuda da equipe de front-end da plataforma em um dia sem alterar o código do site. Não há truques e registros - apenas nginx, docker e node.js (opcional).

Porque
Agora, os aplicativos front-end pesam muito. Os artefatos coletados podem pesar de 2 a 3 MB ou mais. No entanto, algoritmos de compactação ajudam os usuários.
Até recentemente, usamos apenas o Gzip, que foi introduzido no mundo em 1992. Esse é provavelmente o algoritmo de compactação mais popular da Web. Ele é suportado por
todos os navegadores acima do IE 6.Deixe-me lembrá-lo de que o nível de compactação do Gzip varia no intervalo de 1 a 9 (mais é mais eficiente) e você pode compactá-lo em tempo real ou estaticamente.
- “On the fly” (dinamicamente) - os artefatos são armazenados no formulário recebido após a montagem, sua compactação ocorre durante a entrega ao cliente. No nosso caso, no nível nginx.
- Estático - os artefatos são compactados após a montagem e o servidor HTTP os envia ao cliente "como estão".
Obviamente, a primeira opção requer mais recursos do servidor para cada solicitação. O segundo está na fase de montagem e preparação da aplicação.
Nosso frontend foi compactado dinamicamente pelo quarto nível. Vou demonstrar a diferença entre um artefato compactado e o original:
Você pode perceber que até o quarto nível reduz o tamanho do artefato em 4 vezes! E a diferença entre o quarto nível e o nono é de 35 Kb, ou seja, 1,3% do original, mas o tempo de compactação é 2 vezes maior.
E, recentemente, pensamos: por que não mudar para Brotli? Sim, e no nível mais poderoso de compactação!
A propósito, esse algoritmo foi introduzido pelo Google em 2015 e possui 11 níveis de compactação. Ao mesmo tempo, o quarto nível de Brotli é mais eficaz que o nono no Gzip. Fiquei motivado e rapidamente joguei código para compactar artefatos com o algoritmo Brotli. Os resultados são apresentados abaixo:
No entanto, a tabela mostra que mesmo o primeiro nível de compactação de Brotli demora mais que o nono nível no Gzip. E o último nível - até 8,3 segundos! Isso me alertou.
Por outro lado, o resultado é claramente impressionante. Em seguida, tentei transferir a compactação para o nginx -
pesquise a documentação no Google . Tudo acabou sendo extremamente simples:
brotli on; brotli_comp_level 11; brotli_types text/plain text/css application/javascript;
Ele montou a imagem do docker, lançou o contêiner e ficou terrivelmente surpreso:

O tempo de download do meu arquivo aumentou dez vezes - de 100 ms para 5 segundos! O aplicativo tornou-se impossível de usar.
Tendo estudado a documentação mais profundamente, percebi que você pode distribuir estaticamente. Usei um script escrito anteriormente, compactou os mesmos artefatos, coloquei em um contêiner e o iniciei. Os tempos de download voltam ao normal - vitória! No entanto, é muito cedo para se alegrar, porque a proporção de navegadores que suportam esse tipo de compactação é de
cerca de 80% .
Isso significa que você deve manter a compatibilidade com versões anteriores, além de querer usar o nível mais eficaz do Gzip. Então surgiu a idéia de criar um utilitário de compactação de arquivos, que mais tarde recebeu o nome de "Jackal".

Do que precisamos?
Nginx, Docker e Node.js, embora você também possa usar o bash, se desejar.
Com o Nginx, quase tudo fica claro:
brotli off; brotli_static on; gzip_static on;
Mas o que fazer com aplicativos que ainda não conseguiram atualizar a imagem do docker? Certo, adicione compatibilidade com versões anteriores:
gzip on; gzip_level 4; gzip_types text/plain text/css application/javascript;
Vou explicar o princípio de operação:
A cada solicitação, o cliente envia um cabeçalho Accept-Encoding, que lista os algoritmos de compactação suportados, separados por vírgulas. Geralmente é deflate, gzip, br.
Se o cliente tiver br na linha, o nginx procurará arquivos com a extensão .br, se não houver esses arquivos e o cliente oferecer suporte ao Gzip, procurará .gz. Se não houver esses arquivos, ele tremerá "em movimento" e retornará com o quarto nível de compactação.
Se o cliente não suportar nenhum tipo de compactação, o servidor emitirá artefatos em sua forma original.
No entanto, surgiu um problema: nossa imagem do docker nginx não suporta o módulo Brotli. Como base, tirei a
imagem da janela de encaixe finalizada .
Arquivo de encaixe para "empacotar" nginx em um projeto FROM fholzer/nginx-brotli # RUN rm -rf /usr/share/nginx/html/ # COPY app/nginx /etc/nginx/conf.d/ # COPY dist/ /usr/share/nginx/html/ # CMD nginx -c /etc/nginx/conf.d/nginx.conf
Descobrimos o balanceamento de tráfego, mas de onde obter artefatos? É aqui que o Chacal vem em socorro.
O Chacal
Este é um utilitário para compactar as estáticas do seu aplicativo.
Agora, esses são três scripts node.js. agrupados em uma imagem do docker com o nó: alpine. Vamos revisar os scripts.
compressor de base - um script que implementa a lógica básica de compactação.
Argumentos de entrada:
- Função de compactação - qualquer função javascript, você pode implementar seu próprio algoritmo de compactação.
- Parâmetros de compressão - um objeto com parâmetros necessários para a função transferida.
- Extensão - expansão de artefatos de compactação. Deve ser especificado começando com um caractere de ponto.
gzip.js - um arquivo com uma chamada de compressor base com a função Gzip passada do pacote
zlib e indicando o nono nível de compactação.
brotli.js - arquivo com uma chamada de compressor base com a função Brotli passada do
mesmo pacote npm e indicando o 11º nível de compactação.
Dockerfile criando a imagem Jackal FROM node:8.12.0-alpine # COPY scripts scripts # package.json package-lock.json COPY package*.json scripts/ # WORKDIR scripts # # node_modules/ # , RUN npm ci # CMD node gzip.js | node brotli.js
Descobrimos como funciona, agora você pode executar com segurança:
docker run \ -v $(pwd)/dist:/scripts/dist \ -e 'dirs=["dist/"]' \ -i mngame/shakal
- -v $ (pwd) / dist: / scripts / dist - especifique qual diretório local considerar o diretório no contêiner (link para a montagem). É necessário especificar o diretório de scripts, pois está funcionando dentro do contêiner.
- -e 'dirs = ["dist /"]' - especifique o parâmetro do ambiente dirs - uma matriz de linhas que descreve os diretórios dentro dos scripts / que serão compactados.
- -i mngame / shakal - especificando uma imagem com o docker.io.
Nos diretórios especificados, o script compacta recursivamente todos os arquivos com as extensões especificadas .js, .json, .html, .css e salva os arquivos com as extensões .br e .gz ao lado. Em nosso projeto, esse processo leva cerca de dois minutos com o peso de todos os artefatos de cerca de 6 MB.
Nesse ponto, e talvez até mais cedo, você pode ter pensado: “Que janela de encaixe? Qual nó? Por que não adicionar dois pacotes a si mesmo no package.json do projeto e ligar diretamente para o postbuild? ”
É muito doloroso para mim ver quando, para fins de execução de linters no CI, o projeto instala mais de 100 pacotes para si, dos quais precisa no máximo de 10 na fase de espera.
No caso da janela de encaixe, obtemos uma imagem pré-montada na qual tudo o necessário para a compactação está instalado. Se você não precisar compactar nada agora - não compactar. Precisa de um cotão - execute apenas, precisa de testes - execute apenas eles. Além disso, temos uma boa versão do Jackal: não precisamos atualizar suas dependências em cada projeto - basta lançar uma nova versão e usar a tag mais recente para o projeto.
Resultado:
- O tamanho dos artefatos mudou de 636 Kb para 446 Kb.
- O tamanho da porcentagem diminuiu 30%.
- O tempo de download diminuiu de 10 a 12%.
- O tempo de descompressão, com base no artigo , permanece o mesmo.
Total
Você pode ajudar seus usuários agora mesmo, no próximo PR: adicione uma etapa após a montagem - compressão "Chacal" e entregue artefatos ao seu contêiner. Após meia hora, seus usuários se sentem um pouco melhor.
Conseguimos reduzir o peso do front-end em 30% - você terá sucesso! Todos os sites fáceis.
Referências: