Logo David Burdelak
Webdevelopment

Brotli czy Gzip? Jak włączyć szybszą kompresję plików na serwerze?

Porównanie kompresji Brotli i Gzip na serwerze www pod kątem wydajności strony

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

CechaGzipBrotli
Rozmiar plikówpunkt odniesieniazwykle o 15–20% mniejsze pliki JS, CSS i HTML
Szybkość kompresji w lociebardzo szybkaporównywalna na poziomach 4–6, bardzo wolna na 10–11
Szybkość dekompresjibardzo szybkabardzo szybka
Obsługa w przeglądarkachwszystkiewszystkie współczesne, tylko przez HTTPS
Obsługa na serwerachwbudowana praktycznie wszędziewymaga 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 .br bez ż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ść br oznacza Brotli, gzip Gzip, a puste pole brak kompresji.
  • curl. Polecenie curl -sI -H "Accept-Encoding: br" https://twojadomena.pl/ pokazuje nagłówek Content-Encoding w 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.