Większość studiów przypadku PageSpeed oszukuje. Pokazują niemal pusty motyw demo z grafiką główną, trzema produktami i bez realnych modułów, zdobywają 100 punktów i nazywają to dowodem. To niczego nie dowodzi, każdy pusty PrestaShop wypada dobrze. Trudne pytanie, które naprawdę zadaje sobie każdy właściciel sklepu, brzmi inaczej: czy sklep, który wykonuje prawdziwą pracę, slidery, megamenu, jednostronicową realizację zamówienia, wyszukiwanie na żywo, blog, popupy, program lojalnościowy, analitykę. Nadal może być szybki? W tym wpisie odpowiadamy na to pytanie na przykładzie naszego własnego sklepu produkcyjnego, a nie środowiska testowego.

Sprawdzono na działającej stronie głównej mypresta.rocks opartej na PrestaShop 9.1. Poniższe wyniki pochodzą z Google PageSpeed Insights dla naszej strony produkcyjnej, a nie z kopii stagingowej ani lokalnego narzędzia.

mypresta.rocks działa na PrestaShop 9.1 z ponad 80 aktywnymi modułami, i nie chodzi o lekkie moduły służące wyłącznie do konfiguracji. To moduły, które dostarczają własny CSS i JavaScript, podpinają się pod część sklepu widoczną dla klienta oraz renderują widoczne, interaktywne elementy: animowane slidery, rozwijane megamenu, pełną jednostronicową realizację zamówienia, silnik bloga z komentarzami i udostępnianiem, widget wyszukiwania na żywo, kanały z mediów społecznościowych, galerie produktów, popupy sprzedażowe, liczniki odliczające czas, baner zgody na cookies, lojalność, panele analityczne. To dokładnie taki zestaw, który zwykle niszczy wynik PageSpeed. U nas utrzymuje się na poziomie 99.

Ten artykuł to studium przypadku: rzeczywiste liczby z naszej działającej strony głównej oraz struktura procesu, który je daje. Celowo nie jest to ogólny poradnik typu „jak przyspieszyć PrestaShop”, w sprawach mechaniki odsyłamy do powiązanych poradników, które dokładnie omawiają poszczególne tematy, żebyś mógł wejść tak głęboko, jak potrzebujesz, bez powtarzania tych samych informacji.

Wyniki zmierzone przez Google, nie przez nas

Pochodzą z Google PageSpeed Insights, które uruchamia Lighthouse na własnej infrastrukturze Google i testuje naszą działającą stronę główną. To nie są liczby z lokalnego narzędzia, które można wygładzić; to wynik tego samego raportu, który każdy sprzedawca może sprawdzić właśnie teraz.

KategoriaUrządzenia mobilneKomputer
Wydajność9999
Dostępność9797
Najlepsze praktyki100100
SEO100100

Wynik wydajności jest ważoną mieszanką laboratoryjnych metryk Core Web Vitals, dlatego metryki stojące za liczbą są ważniejsze niż sama liczba. Oto pełny rozkład dla obu typów urządzeń.

MetrykaUrządzenia mobilne (Slow 4G, Moto G Power)Komputer
First Contentful Paint (FCP)1.2s0.3s
Largest Contentful Paint (LCP)1.5s0.9s
Total Blocking Time (TBT)110ms30ms
Cumulative Layout Shift (CLS)00.011
Speed Index (SI)1.4s0.5s

Kolumna mobilna jest tą, która naprawdę się liczy. Google indeksuje w modelu mobile-first i ogranicza test mobilny do profilu Slow 4G na telefonie ze średniej półki, co jest znacznie bardziej wymagające niż test komputerowy na szybkim łączu. LCP na poziomie 1.5s i CLS równe dokładnie 0 przy takim ograniczeniu, z ponad 80 modułami na produkcji, to wynik, który chcieliśmy pokazać. Co Ci to daje? Sklep, w którym strona staje się użyteczna mniej więcej po sekundzie na prawdziwym telefonie i prawdziwej sieci, czyli tam, gdzie faktycznie odbywa się większość ruchu i większość porzuceń.

Dlaczego ponad 80 modułów jest tu sednem sprawy

Liczba modułów to zmienna, której wszyscy się boją, a której prawie nikt uczciwie nie mierzy. Każdy moduł działający po stronie sklepu w PrestaShop zwykle dodaje trzy koszty: dodatkowy CSS, dodatkowy JavaScript i dodatkowe wykonanie hooków przy każdym renderowaniu strony. System CCC w PrestaShop (Zaawansowane → Wydajność, „Combine, Compress and Cache”) zmniejsza i łączy kwalifikujące się pliki CSS oraz JS, często do znacznie mniejszej liczby wygenerowanych plików. Dokładna liczba zależy od tego, jak motyw i moduły rejestrują zasoby, typy mediów oraz wykluczenia, co rozwiązuje dużą część problemu liczby żądań, ale tworzy problem wagi danych: w naszym sklepie połączony arkusz stylów miał przed obróbką ponad 850KB, a przytłaczająca większość reguł nigdy nie była używana na stronie głównej.

To jest prawdziwy powód, dla którego ciężkie sklepy sprawiają wrażenie wolnych, nie „za dużo modułów” jako zarzut sam w sobie, lecz megabajty połączonego CSS/JS, które blokują pierwsze renderowanie, gdy przeglądarka analizuje reguły i skrypty, których odwiedzający nigdy nie uruchomi. Jeśli chcesz wersję diagnostyczną, jak rozpoznać, która warstwa naprawdę Ci szkodzi, to temat powiązany, opisany we wpisach co naprawdę spowalnia PrestaShop oraz w procesie sprawdzania w czy Twój sklep jest wolny i jak to sprawdzić. Tutaj najważniejsze jest to, że zostawiliśmy wszystkie ponad 80 modułów i zaatakowaliśmy wagę zasobów zamiast usuwać funkcje.

Jak zbudowany jest proces, warstwa po warstwie

Nie ma jednego przełącznika. Wynik 99 to suma zdyscyplinowanego procesu, który dotyka ścieżki renderowania na każdej warstwie. Poniżej opisujemy, co robi każdy etap i, co ważniejsze, dlaczego realnie poprawia wynik, z odnośnikami do szerszej teorii tam, gdzie temat należy do osobnego poradnika.

Wyodrębnienie krytycznego CSS i ładowanie asynchroniczne

CSS blokujący renderowanie jest największym wrogiem szybkiego pierwszego wyświetlenia: przeglądarka niczego nie narysuje, dopóki nie ma arkusza stylów. Wstawienie całego pliku 500KB+ inline byłoby gorsze, nie lepsze. Zamiast tego wyodrębniamy krytyczny CSS above-the-fold dla strony i umieszczamy bezpośrednio w HTML tylko ten mały fragment; pełny połączony arkusz stylów jest następnie ładowany asynchronicznie wzorcem podmiany media="print" onload, dzięki czemu pobiera się w tle bez blokowania. Przeglądarka natychmiast renderuje stronę przy użyciu wstawionych krytycznych stylów, a po dotarciu pełnego arkusza przełącza się na niego. Korzyść: strona jest widoczna po około sekundzie, zamiast czekać na pół megabajta CSS, a ponieważ krytyczny fragment już styluje to, co jest na ekranie, podmiana nie powoduje żadnego przesunięcia układu.

Czyszczenie CSS z nieużywanych reguł

Przy ponad 80 modułach połączony CSS niesie tysiące selektorów, które na danej stronie nigdy do niczego nie pasują. Uruchamiamy PurgeCSS na rzeczywiście wyrenderowanym HTML kluczowych typów stron oraz na każdym pliku JavaScript i szablonie w motywie oraz modułach, dzięki czemu klasy przełączane dynamicznie zostają zachowane. W naszym sklepie zmniejszyło to arkusz stylów z 852KB do 548KB, o 36%. Mniej CSS oznacza mniej danych do pobrania na Slow 4G, mniej analizowania na procesorze ze średniej półki i szybszą podmianę bez przesunięć.

Dzielenie i odraczanie JavaScriptu

Nie każdy JavaScript musi działać, zanim strona stanie się interaktywna. Dzielimy pakiet JavaScript CCC na dwie części:

  • Pakiet synchroniczny (~140KB / 41KB gzip): tylko rdzeń, którego strona naprawdę potrzebuje wcześnie, jQuery i podstawowe skrypty PrestaShop.
  • Pakiet odroczony (~497KB / 111KB gzip): Bootstrap, skrypty motywu i niekrytyczne skrypty modułów, ładowane z atrybutem defer, aby wykonały się po sparsowaniu dokumentu.

Odraczanie ciężkiego pakietu trzyma go z dala od głównego wątku w krytycznym oknie, co obniża Total Blocking Time do 110ms na urządzeniach mobilnych i 30ms na komputerze. TBT to metryka, na której sklepy z dużą liczbą modułów wykładają się najczęściej, bo skrypt każdego modułu chce uruchomić się jednocześnie podczas ładowania.

Inteligentne ładowanie zasobów zależne od strony

Najbardziej marnotrawnym wzorcem wydajnościowym w PrestaShop jest wysyłanie JavaScriptu obsługującego realizację zamówienia i płatności do odwiedzających, którzy czytają blog. Ładujemy zasoby z uwzględnieniem kontekstu: JavaScript realizacji zamówienia (ponad 180KB po minifikacji) jest w pełni odroczony na stronach poza realizacją zamówienia, pobierany przez requestIdleCallback na stronie głównej i stronach treści, aby był gotowy, gdy okaże się potrzebny, ale nigdy nie konkurował podczas pierwszego renderowania, oraz ładowany natychmiast wyłącznie na stronach produktu, koszyka i realizacji zamówienia, gdzie faktycznie jest używany. JavaScript płatności Stripe jest całkowicie usuwany ze stron poza realizacją zamówienia. I co z tego? Klient trafiający na wpis blogowy albo kategorię nie płaci kosztem pobierania i wykonywania kodu realizacji zamówienia, na którym jeszcze nie jest.

Optymalizacja obrazów bez narzutu PHP

Obrazy są zwykle elementem LCP, więc decydują o metryce o największej wadze. Każdy obraz produktu i banera serwujemy jako AVIF przez negocjację treści w Apache, podmiana na nowoczesny format odbywa się na warstwie serwera WWW, bez żadnego narzutu PHP przy każdym żądaniu. Nasz konwerter wsadowy przetworzył 5,399 obrazów i zmniejszył łączny rozmiar magazynu obrazów z 994MB do 44MB (o 95.6% mniej). Mobilny baner główny ma ostatecznie 25KB, wersja desktopowa 56KB, oba w jakości, po której nie zauważysz kompresji.

Po stronie Apache to po prostu negocjacja treści: podaj wcześniej wygenerowany .jpg.avif albo .png.avif tylko wtedy, gdy przeglądarka deklaruje obsługę AVIF, i zachowaj Vary: Accept, żeby pamięci podręczne nie mieszały formatów.

<IfModule mod_rewrite.c>
  RewriteEngine On
  RewriteCond %{HTTP_ACCEPT} image/avif
  RewriteCond %{DOCUMENT_ROOT}/$1.$2.avif -f
  RewriteRule ^(.+)\.(jpe?g|png)$ $1.$2.avif [T=image/avif,E=avif:1,L]
</IfModule>

<IfModule mod_headers.c>
  Header append Vary Accept env=avif
</IfModule>

Raport optymalizacji zasobów Performance Revolution

Przegląd optymalizacji zasobów pokazuje karty stanu dla optymalizacji zasobów, Critical CSS, PurgeCSS i lazy loading oraz panele CSS, JavaScript i obrazów z liczbą plików i rozmiarami na zerze, nad pustą listą zasobów.

Jedna nieintuicyjna lekcja jest warta więcej niż jakiekolwiek ustawienie: preloadujemy tylko mobilny obraz LCP i nic więcej. Na Slow 4G przy około 200KB/s każdy dodatkowy preload konkuruje z krytycznym CSS o to samo wąskie łącze. Preload fontu webowego albo banera desktopowego pogarszał u nas mobilny FCP. Zmierzyliśmy to, wycofaliśmy zmianę i ta powściągliwość jest częścią powodu, dla którego LCP kończy na 1.5s.

Dostępność jako świadomy cel, nie efekt uboczny

Wynik dostępności 97 został wypracowany, a nie przypadkowo trafiony. Wymagał dopilnowania kontrastu WCAG 2.1 AA dla każdego elementu (4.5:1 dla tekstu podstawowego, 3:1 dla dużego tekstu), widocznych wskaźników fokusu na elementach interaktywnych, poprawnej hierarchii nagłówków z etykietami ARIA oraz właściwego użycia narzędzia visually-hidden, aby czytniki ekranu otrzymywały treść ukrytą wizualnie. Dlaczego właściciel sklepu powinien się tym przejmować: ta sama dyscyplina, która czyni stronę dostępną, uczciwy kontrast, brak skoków układu, przewidywalny fokus, utrzymuje CLS na poziomie 0 i chroni realnych klientów przed błędnymi kliknięciami. Dostępność i konwersja idą w tym samym kierunku.

Wąskie gardło renderowania, które sami spowodowaliśmy, a potem naprawiliśmy, uczciwa część

Nic z tego nie było idealne za pierwszym razem, a najpożyteczniejsza lekcja przyszła z regresji, którą sami wprowadziliśmy. W pewnym momencie renderowanie naszych stron po stronie serwera wzrosło do około 2.2 sekundy. Wystarczająco wolno, by praca front-endowa opisana wyżej była niwelowana, zanim choć jeden bajt opuścił serwer. Przyczyną nie był motyw ani baza danych. Proces zasobów hashował każdy połączony pakiet przy każdym żądaniu, aby zbudować jego klucz pamięci podręcznej: po podziale połączonych CSS/JS na wiele plików oznaczało to liczenie sha1 dla około 670 pakietów przy każdym pojedynczym ładowaniu strony. To hashowanie było czystym narzutem powtarzanym przy każdej wizycie i zdominowało renderowanie.

Naprawa polegała na tym, żeby przestać przeliczać coś, co nie zmienia się między żądaniami, przechowywać odciski pakietów w pamięci podręcznej zamiast ponownie hashować pliki za każdym razem, i czas renderowania wrócił tam, gdzie powinien. Wspominamy o tym, bo to koszt, który nigdy nie pojawia się w laboratoryjnym teście PageSpeed na rozgrzanej stronie; można go złapać tylko, obserwując rzeczywisty czas generowania po stronie serwera pod ruchem. Jeśli TTFB jest wysokie, a metryki front-endowe wyglądają dobrze, wąskim gardłem jest coś, co serwer powtarza przy każdym żądaniu, i jedyny sposób, żeby to znaleźć, to mierzyć czas generowania strony, a nie wynik na nagłówku raportu.

Drugą połową utrzymania stabilnego wyniku jest dopilnowanie, żeby odwiedzający i Google trafiali na stronę rozgrzaną, a nie zimną. Uruchamiamy mechanizm rozgrzewania pamięci podręcznej dla pełnego zestawu adresów URL, rzędu 6,625 URL-i, dzięki czemu pierwszy prawdziwy odwiedzający dowolną stronę nie jest tym, który płaci czasem za jej ponowne wygenerowanie. Cache pomaga tylko tym żądaniom, które trafiają po jego wypełnieniu; celowe rozgrzewanie zmienia „szybko dla drugiego odwiedzającego” w „szybko dla pierwszego”.

Czego to studium przypadku celowo nie obejmuje

Optymalizacja renderowania front-endu to tylko połowa szybkości sklepu. Druga połowa dzieje się na serwerze, zanim choć jeden bajt dotrze do przeglądarki, czas zapytań do bazy danych, cache obiektów, pełnostronicowa pamięć podręczna i hosting, a każdy z tych tematów jest na tyle głęboki, że zasługuje na własny poradnik zamiast jednego akapitu tutaj. Porządne omówienie ich w innych miejscach pozwala nam też uniknąć mówienia Ci tego samego pięć razy w pięciu wpisach.

Jak odtworzyć to we własnym sklepie

Jeśli weźmiesz powyższe liczby i spróbujesz zweryfikować zmianę w swoim sklepie, zrób to w sposób odporny na krytykę, a nie taki, który daje fałszywe poczucie poprawy. Zanim czegokolwiek dotkniesz, uruchom PageSpeed Insights dla strony, na której Ci zależy, i zapisz cztery laboratoryjne metryki wpływające na wynik, LCP, TBT, CLS i Speed Index, oddzielnie dla urządzeń mobilnych i komputerów, bo zmieniają się niezależnie. Wprowadzaj jedną kategorię zmian naraz (CSS, potem JS, potem obrazy), testuj ponownie i zostawiaj zmianę tylko wtedy, gdy metryka, na którą była skierowana, rzeczywiście się poprawiła. Lekcja z preloadem powyżej jest ostrzeżeniem: zmiana, która brzmi jak optymalizacja, może pogorszyć mobilny FCP, a zauważysz to tylko wtedy, gdy mierzysz przed i po, zamiast ufać opisowi produktu.

Jedno uczciwe zastrzeżenie dotyczące samych wyników: laboratoryjne rezultaty PageSpeed różnią się o kilka punktów między uruchomieniami i zależą od testowanej strony oraz aktualnego obciążenia serwera. Traktuj 99 jako „konsekwentnie świetnie”, a nie stałą wartość, stabilny pozostaje kształt wyniku: mobilny LCP poniżej 2 sekund i CLS bliskie zeru w w pełni wyposażonym sklepie.

Pytania, które zwykle pojawiają się przy tym studium przypadku

Czy usunęliście moduły, żeby osiągnąć 99? Nie, na tym polega cały sens. Wszystkie ponad 80 modułów działających po stronie sklepu pozostało aktywnych: slidery, megamenu, jednostronicowa realizacja zamówienia, wyszukiwanie na żywo, blog, popupy, lojalność, analityka. Zaatakowaliśmy wagę zasobów, krytyczny CSS, czyszczenie CSS, podział i odroczenie JS, AVIF, a nie listę funkcji. Wynik osiągnięty przez usunięcie funkcji nie jest rezultatem, z którego może skorzystać prawdziwy sklep.

Czy to tylko sztuczki front-endowe, czy serwer też ma znaczenie? Jedno i drugie, ale to dwie oddzielne połowy. Wszystko w tym studium przypadku jest optymalizacją renderowania front-endu, sprawia, że strona szybko się wyświetla, gdy PHP wyprodukuje HTML. Serwer nadal musi szybko wyprodukować ten HTML, a to oznacza bazę danych, cache obiektów (Redis), pełnostronicową pamięć podręczną i hosting, omówione w powiązanych poradnikach. Opisane wyżej wąskie gardło renderowania jest dowodem: wolny czas generowania po stronie serwera pogrąży dobry wynik front-endowy, a zobaczysz to tylko, mierząc TTFB, nie samą liczbę na górze raportu.

Czy mój wynik się utrzyma, czy będzie skakał? Laboratoryjne wyniki PageSpeed różnią się o kilka punktów między uruchomieniami i zależą od testowanej strony oraz aktualnego obciążenia serwera. Traktuj 99 jako „konsekwentnie świetnie”, a nie stałą wartość. Stabilny pozostaje kształt, mobilny LCP poniżej 2 sekund i CLS bliskie zeru, bo wynika z całego procesu, a nie ze szczęśliwego przebiegu testu.

Czy to przestanie działać po aktualizacji PrestaShop albo motywu? Proces działa na warstwie zasobów zamiast forkować motyw, więc nie walczy z aktualizacją rdzenia ani motywu tak jak ręcznie edytowany motyw. To celowe, optymalizacja renderowania, która psuje się przy następnej aktualizacji, nie jest warta wyniku, który dała.

Dlaczego preloadować tylko mobilny obraz LCP? Bo na Slow 4G przy około 200KB/s każdy dodatkowy preload konkuruje z krytycznym CSS o to samo wąskie łącze. Zmierzyliśmy, że preload fontu webowego albo banera desktopowego pogarszał mobilny FCP jeszcze bardziej, wycofaliśmy to i ta powściągliwość jest częścią powodu, dla którego LCP kończy na 1.5s. Preload to skalpel, nie ustawienie domyślne.

Gdzie wchodzą w to moduły

Powód, dla którego to studium przypadku istnieje, jest prosty: każda z powyższych technik nie jest jednorazowym rozwiązaniem zbudowanym ręcznie dla naszej strony i zatrzymanym dla siebie. Jest spakowana w moduł. W konfiguracji, którą mierzyliśmy dla tego studium przypadku, moduł Performance Revolution jest procesem stojącym za tymi liczbami. Działający raport PageSpeed naszej strony głównej jest dowodem: wyodrębnienie krytycznego CSS i asynchroniczna podmiana, czyszczenie CSS, podział JavaScriptu na synchroniczny i odroczony, odraczanie zasobów realizacji zamówienia i Stripe zależne od strony oraz dostarczanie obrazów AVIF. Co to oznacza dla Ciebie? Dostajesz optymalizację front-endu, która dała ten wynik 99, konfigurowaną z panelu administracyjnego zamiast płacić programiście za ręczne odbudowanie procesu renderowania, a ponieważ działa na warstwie procesu zasobów zamiast forkować motyw, nie psuje się przy następnej aktualizacji.

Front-end to połowa stosu, dlatego łączymy go z Redis Cache Manager & Monitor do serwerowego cache obiektów, proces front-endowy sprawia, że strona renderuje się szybko, gdy PHP ją wyprodukuje, a Redis sprawia, że PHP produkuje ją szybciej. Razem obejmują obie połowy problemu szybkości, który opisuje ten wpis i jego serwerowe odpowiedniki.

Wniosek jest wąski i uczciwy: prawdziwy sklep PrestaShop 9.1 z ponad 80 aktywnymi, ciężkimi front-endowo modułami może osiągać 99/100 w tym samym teście Google, którego używasz do oceny własnego sklepu. Nie wymaga to usuwania funkcji ani pustego motywu demo. Wymaga zaatakowania wagi zasobów zamiast listy funkcji, mierzenia każdej zmiany na profilu mobilnym, który Google faktycznie waży, oraz traktowania warstw serwerowych, bazy danych, pełnostronicowej pamięci podręcznej, Redis, hostingu, jako drugiej połowy zadania, a nie refleksji po fakcie.

David Miller

David Miller

Założyciel, mypresta.rocks
O autorze

David Miller to specjalista PrestaShop z ponad dekadą praktycznego doświadczenia i założyciel mypresta.rocks, studia programistycznego z miasta Tychy. Tworzy i utrzymuje katalog 159 modułów PrestaShop, w tym 21 pakietów „Revolution" obejmujących SEO, checkout, bezpieczeństwo, wydajność, marketing, wyszukiwanie, wsparcie i operacje magazynowe, które każdego dnia usprawniają realne sklepy, testowanych na PrestaShop 1.7.8, 8.x i 9.x. Sprawuje również opiekę nad sklepami produkcyjnymi, dlatego jego pracę ocenia się po realnej sprzedaży, a nie po wersjach demo. Jego doświadczenie obejmuje pełen zakres e-commerce, wydajność, bezpieczeństwo, SEO i marketing, oraz wykracza poza PrestaShop, sięgając WooCommerce, Shopify i systemów tworzonych na zamówienie. Na blogu pisze o technicznej stronie PrestaShop: co platforma naprawdę robi pod maską, co psuje się na produkcji i które rozwiązania faktycznie się sprawdzają.

Udostępnij ten wpis:

Komentarze

Brak komentarzy. Bądź pierwszy!

Spodobał Ci się ten artykuł?

Otrzymuj nasze najnowsze porady, przewodniki i aktualizacje modułów prosto na swoją skrzynkę.

Możesz zrezygnować w każdej chwili. Dane kontaktowe znajdziesz w naszej nocie prawnej.

Ładowanie...
Do góry