Kompresja plików tekstowych to jedna z najtańszych optymalizacji wydajności, a mimo to przy audytach regularnie trafiam na strony, które wysyłają HTML, CSS i JavaScript w ogóle bez kompresji albo tylko z Gzipem ustawionym lata temu. Brotli zmniejsza te same pliki o kolejne kilkanaście procent, a wdrożenie zajmuje zwykle kilka minut. W tym wpisie pokazuję, czym Brotli różni się od Gzipa w praktyce, jak go włączam na Apache, Nginx i w CDN oraz jak sprawdzam, czy serwer faktycznie z niego korzysta.
Brotli i Gzip w praktyce
| Cecha | Gzip | Brotli |
|---|---|---|
| Rozmiar plików | punkt odniesienia | zwykle o 15–20% mniejsze pliki JS, CSS i HTML |
| Szybkość kompresji w locie | bardzo szybka | porównywalna na poziomach 4–6, bardzo wolna na 10–11 |
| Szybkość dekompresji | bardzo szybka | bardzo szybka |
| Obsługa w przeglądarkach | wszystkie | wszystkie współczesne, tylko przez HTTPS |
| Obsługa na serwerach | wbudowana praktycznie wszędzie | wymaga modułu na Apache i Nginx, w CDN zwykle domyślnie |
Przewaga Brotli wynika z wbudowanego słownika typowych fragmentów HTML, CSS i JavaScriptu oraz lepszego modelowania danych. Największą różnicę widać przy dużych plikach JavaScript, które w wielu projektach są najcięższą częścią strony.
Nie oznacza to, że Gzip trzeba wyłączyć. Zostawiam oba: przeglądarka wysyła w nagłówku Accept-Encoding listę obsługiwanych
metod, a serwer wybiera najlepszą. Ze starszymi klientami i niektórymi narzędziami, które nie obsługują Brotli, nadal porozumiewa się Gzipem.
Poziom kompresji, czyli gdzie łatwo przesadzić
Brotli ma poziomy od 0 do 11. Najwyższe dają najmniejsze pliki, ale kompresja trwa wtedy nieporównanie dłużej. Dlatego rozróżniam dwa przypadki:
- Kompresja w locie, czyli dla HTML generowanego przez PHP czy Node.js przy każdym żądaniu: poziom 4–6. Wyższy poziom wydłużyłby czas odpowiedzi serwera bardziej, niż skróciłby czas przesyłania.
- Pliki statyczne, czyli zbudowane paczki CSS i JS: poziom 11, ale tylko raz, na etapie budowania projektu. Serwer wysyła potem
gotowy plik
.brbez żadnych obliczeń.
Wstępnie skompresowane pliki generuję razem z resztą zasobów, np. poleceniem brotli -q 11 dist/*.js dist/*.css albo wtyczką
do bundlera, i serwuję je, gdy przeglądarka obsługuje Brotli.
Włączenie Brotli na Apache
Apache od wersji 2.4.26 ma moduł mod_brotli. Na hostingach współdzielonych często jest już włączony, a reguły dodaję w
pliku .htaccess, obok Gzipa jako zapasowej metody:
<IfModule mod_brotli.c>
BrotliCompressionQuality 5
AddOutputFilterByType BROTLI_COMPRESS text/html text/css text/plain text/xml application/javascript application/json application/xml image/svg+xml
</IfModule>
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html text/css text/plain text/xml application/javascript application/json application/xml image/svg+xml
</IfModule>
Na serwerach LiteSpeed, popularnych na polskich hostingach, Brotli włącza się zwykle w panelu albo działa domyślnie, a reguły
mod_brotli są po prostu pomijane.
Włączenie Brotli na Nginx
Nginx nie ma Brotli w standardowej dystrybucji. Potrzebny jest moduł ngx_brotli, dostępny w repozytoriach części dystrybucji
Linuksa albo w obrazach Docker z rozszerzeniami. Po jego załadowaniu konfiguracja wygląda tak:
brotli on;
brotli_comp_level 5;
brotli_static on; # serwuje gotowe pliki .br, jeśli istnieją
brotli_types text/css text/plain text/xml application/javascript application/json application/xml image/svg+xml;
gzip on;
gzip_vary on;
gzip_types text/css text/plain text/xml application/javascript application/json application/xml image/svg+xml;
Typu text/html nie trzeba wymieniać, bo jest kompresowany zawsze. Nie dodaję natomiast zdjęć JPEG, WebP, AVIF ani czcionek WOFF2,
bo są już skompresowane i ponowna kompresja tylko zużyłaby procesor.
Brotli w CDN
Jeśli strona działa za CDN, kompresja często dzieje się właśnie tam. Cloudflare czy Bunny kompresują odpowiedzi Brotli do przeglądarki niezależnie
od tego, jak serwer wysłał je do CDN. W takiej konfiguracji pilnuję dwóch rzeczy: żeby serwer wysyłał nagłówek Vary: Accept-Encoding
i żeby CDN nie przechowywał w pamięci podręcznej wersji skompresowanej dla klienta, który kompresji nie obsługuje. To jeden z punktów,
które sprawdzam przy każdej konfiguracji CDN.
Nowsze przeglądarki obsługują już także kompresję Zstandard (zstd), którą zaczynają oferować niektóre CDN. Na razie traktuję ją jako
dodatek, a nie zamiennik Brotli, bo obsługa po stronie serwerów i narzędzi jest jeszcze ograniczona.
Jak sprawdzam, czy kompresja działa
- Narzędzia deweloperskie. W zakładce Network dodaję kolumnę Content-Encoding i porównuję rozmiar przesłany z rozmiarem pliku.
Wartość
broznacza Brotli,gzipGzip, a puste pole brak kompresji. - curl. Polecenie
curl -sI -H "Accept-Encoding: br" https://twojadomena.pl/pokazuje nagłówekContent-Encodingw odpowiedzi. - PageSpeed Insights. Diagnoza „Włącz kompresję tekstu” wskazuje pliki, które nadal przychodzą bez kompresji.
Mniejsze pliki CSS i JavaScript to szybsze pobranie zasobów blokujących renderowanie, a więc realny zysk przy optymalizacji LCP. Kompresja nie zastąpi jednak usunięcia zbędnego kodu ani pamięci podręcznej przeglądarki, dzięki której powracający użytkownik w ogóle nie pobiera plików ponownie.