Opublikowano 4 min. czytania

Używając formatu WebP trzeba zmierzyć się z głównym problemem, jakim jest zapewnienie wsparcia dla przeglądarek, które go nie obsługują. Pokażę Ci jak szybko i sensownie wdrożyć WebP na poziomie serwera WWW (NGINX i Apache) bez jakiejkolwiek modyfikacji kodu front- i back-endu strony, która w zależności od jego złożoności, mogłaby być bardzo czasochłonna.

Na obecną chwilę, jak możemy zobaczyć na stronie caniuse.com, wciąż wiele przeglądarek całkowicie nie obsługuje tego formatu (w tym wszystkie wersje Internet Explorer'a oraz Safari):

Obsługa WebP w przeglądarkach

Zainstaluj WebP

W systemie Debian/Ubuntu zrobisz to komendą:

sudo apt-get install cwebp

Możesz również pobrać paczkę libwebp-1.0.3.tar.gz stąd i skompilować ze źródeł:

tar zxf libwebp-1.0.3.tar.gz
cd libwebp-1.0.3
./configure
make
sudo make install

Dzięki temu zainstalujesz cwebp, którym przekonwertujesz pliki.

Przekonwertuj pliki

Na stronie internetowej zazwyczaj nieustannie pojawiają się nowe grafiki (wgrywane przez CMS, automatycznie generowane miniatury itd.), dlatego rozsądnie będzie przygotować skrypt w bash'u, który cyklicznie wywoływany przez cron, będzie rekursywnie we wszystkich podkatalogach wyszukiwał i konwertował nowo powstałe pliki .jpg/.jpeg/.png do .webp i umieszczał je obok oryginalnych.

Utwórz plik convert_to_webp.sh o zawartości:

#!/bin/bash

OLD_IFS=$IFS
IFS=$(echo -en "\n\b")

for FILE in `find /var/www/example.com/public/ -iregex '.*\.\(jpg\|gif\|png\|jpeg\)$'`
    do
        if [ ! -f "${FILE}.webp" ]; then
            cwebp -quiet -q 80 ${FILE} -o ${FILE}.webp;
            echo "Converted ${FILE} to ${FILE}.webp"
        fi
done

IFS=$OLD_IFS

Dostosuj w nim ścieżkę /var/www/example.com/public/ tak, aby wskazywała na katalog, w którym znajdują się pliki do przekonwertowania, po czym nadaj skryptowi prawa do wykonywania:

chmod +x convert_to_webp.sh

i uruchom:

./convert_to_webp.sh

Jeśli wszystko zostało wykonane prawidło i w katalogu znajdowały się pliki do przekonwertowania, ujrzysz podobny wynik:

/var/www/example.com/public/photo.jpg has been converted to /var/www/example.com/public/photo.jpg.webp
/var/www/example.com/public/logo.png has been converted to /var/www/example.com/public/logo.png.webp
/var/www/example.com/public/subfolder/background.png has been converted to /var/www/example.com/public/subfolder/background.png.webp

Obok oryginalnych plików powstały ich odpowiedniki w WebP. Warto zauważyć, że ponowne wykonanie skryptu nie przekonwertuje jeszcze raz tych samych plików, dlatego bez obaw nawet przy dużej ilości obrazów można dopisać skrypt do crona, aby przekonwertował nowe pliki, gdy się pojawią.

Aby wywoływać cronem skrypt co 30 minut, wpisz komendę crontab -e, a następnie dodaj linię:

*/30 * * * * /sciezka/do/skryptu/convert_to_webp.sh

Konfiguracja NGINX do serwowania WebP

W głównym pliku konfiguracyjnym nginx.conf (zazwyczaj w /etc/nginx/nginx.conf) w sekcji http {} umieść:

map $http_accept $webp_suffix {
    default   "";
    "~*webp"  ".webp";
}

Następnie w sekcji server {} używanego vhosta, dodaj poniższą dyrektywę:

location ~* ^.+\.(png|jpe?g) {
    add_header Cache-Control "public, no-transform";
    add_header Vary "Accept,Accept-Encoding";
    try_files $uri$webp_suffix $uri =404;
    expires 30d;
}

Sprawi to, że każda przeglądarka, która wraz z requestem HTTP wysyła w nagłówku Accept typ MIME image/webp (co oznacza, że wspiera WebP i robi tak m.in. Chrome), otrzyma w odpowiedzi plik zawartość pliku .webp, jeśli tylko taki istnieje.

Na koniec zrestartuj NGINX, aby zastosować zmiany.

/etc/init.d/nginx restart

Konfiguracja Apache do serwowania WebP

W pliku .htaccess dodaj poniższe dyrektywy:

<IfModule mod_rewrite.c>
  RewriteEngine On

  # Sprawdzenie, czy żądanie dotyczy plików png/jp(e)g
  RewriteCond %{REQUEST_URI} \.(png|jpe?g)$

  # Sprawdzenie, czy przeglądarka obsługuje WebP
  RewriteCond %{HTTP_ACCEPT} image/webp

  # Sprawdzenie, czy plik .webp istnieje
  RewriteCond %{DOCUMENT_ROOT}/$1.webp -f

  # Zwrócenie pliku .webp
  RewriteRule (.+)$ $1.webp [T=image/webp]
</IfModule>

<IfModule mod_setenvif.c>
  # Utworzenie zmiennej REQUEST_IS_IMAGE dla plików png/jpg(e)g
  SetEnvIf Request_URI "\.(png|jpe?g)$" REQUEST_IS_IMAGE
</IfModule>

<IfModule mod_headers.c>
  # Dodanie nagłówka Vary do odpowiedzi informującego,
  # że zawartość pod URL-em z plikiem png/jp(e)g może się różnić
  # w zależności od tego, czy przeglądarka m.in. obsługuje WebP
  Header set Vary "Accept,Accept-Encoding" env=REQUEST_IS_IMAGE
</IfModule>

<IfModule mod_mime.c>
  AddType image/webp .webp
</IfModule>

Ich działanie opiera się na takich samych zasadach, jak w przypadku NGINX.

Zweryfikuj, czy działa

Możesz w tym celu użyć Chrome DevTools. Jeżeli wszystko zostało wykonane poprawnie, podczas żądania pobrania pliku PNG/JPG, w sekcji Response Headers zobaczysz nagłówek Content-Type z wartością "image/webp":

Weryfikacja typu MIME w zwracanym nagłówku Content-Type