Punkt wyjścia
Valibot i Formisch to biblioteki TypeScript z obszerną częścią referencyjną: razem ponad 1100 podstron, z czego 819 przypada na samo valibot.dev. Obie dokumentacje renderowały się na Vercel Edge przy każdym wejściu. Qwik nie hydratuje, tylko wznawia pracę, więc po stronie przeglądarki nie było już czego optymalizować. Wąskie gardło leżało wyżej: każde otwarcie podstrony uruchamiało funkcję, a ustawienia czytelnika trzymały się w ciasteczkach httpOnly odczytywanych przez routeLoader$. HTML powstawał pod konkretne żądanie i z tego powodu nie nadawał się do trzymania w cache.
Dokumentacja nie potrzebuje renderowania w locie
Po zamianie adaptera Vercel Edge na adapter SSG z Qwik Routera każda trasa trafia do wyniku kompilacji jako gotowy plik HTML wraz z towarzyszącym mu q-data.json. Pierwsze wejście dostaje HTML, a kolejne przejścia w obrębie serwisu pobierają już tylko JSON. Nawigacja zachowuje się identycznie jak wcześniej, tyle że po stronie serwera nic się nie liczy.
Ustawienia czytelnika, czyli najtrudniejszy fragment
Przeniesienie ciasteczka do przeglądarki ma rozwiązanie, które samo się narzuca i jest złe. useVisibleTask$ z odczytem localStorage wykonuje się dopiero po narysowaniu strony. Czytelnik widzi najpierw wartość domyślną, a ułamek sekundy później swoją. Przy motywie to mignięcie jasnego tła u kogoś, kto siedzi na ciemnym. Przy przełączniku rozdziałów robi się z tego skok layoutu, bo ta opcja rusza max-width, boczną kolumnę i marginesy treści.
Sprawdza się dopiero decyzja podjęta przed rysowaniem. Blokujący skrypt w head sięga do localStorage i dokłada klasę do elementu html, a arkusz stylów opiera się wyłącznie na tej klasie, nigdy na sygnale dostępnym po wznowieniu. W Tailwindzie v4 stan domyślny jest wariantem bazowym, a własny wariant no-chapters go nadpisuje, na tej samej zasadzie co dark. Sekcja aside z rozdziałami renderuje się zawsze i chowa ją CSS, więc jej ukrycie nie rusza układu. Sygnały zostały w kodzie, ale odpowiadają już tylko za opis przycisku.
Obrazy OG z kompilacji, nie z żądania
Wcześniej podgląd do social mediów rysowała trasa /og-image, uruchamiana przy każdym zapytaniu bota. Teraz PNG dla każdej trasy powstaje raz, podczas kompilacji, i przechodzi przez sharp z kwantyzacją palety. Karty składają się z kilku płaskich kolorów, więc plik chudnie bez widocznej straty. Znacznik w head prowadzi wprost do /og/.png.
Co wolno zamrozić w cache, a czego nie
Pliki z hashem w nazwie, czyli /build, /assets i /fonts, dostają rok i immutable. Z q-data.json tak się nie da: ścieżka jest stała, ale zawartość zmienia się przy każdym wdrożeniu, bo odwołuje się do hashy symboli. Stąd krótkie max-age dla przeglądarki, długie s-maxage dla CDN i tydzień stale-while-revalidate. Przejścia zostają natychmiastowe, a nikt nie utknie z plikiem wskazującym na symbole, których w nowej wersji już nie ma.
Jeden patch do Qwik Routera
SSG dopisywał ukośnik do każdej ścieżki, którą uznał za trasę, również tym zakończonym rozszerzeniem pliku. Część podstron nie trafiała przez to do kompilacji w ogóle, a adresy z kropką, jak .md czy .png, przestawały działać. Patch ogranicza dopisywanie do ścieżek bez znanego rozszerzenia i brakujące trasy wróciły.
Statyczny wynik nie przywiązuje do dostawcy
Z kompilacji wychodzi HTML, JSON, fonty i obrazy, czyli nic, co byłoby związane z konkretnym adapterem. Ten sam katalog postawi u siebie dowolny CDN, więc wybór hostingu można rewidować, kiedy się chce. Dziś obie strony stoją na Cloudflare i przy trafieniu w cache oddają pierwszy bajt w około 80 ms z Europy.
Pierwsza realizacja w OSS Partner Program
To pierwsze wdrożenie w ramach naszego OSS Partner Program. Zdejmujemy z zespołów open source powtarzalną robotę wokół infrastruktury i utrzymania, żeby ich czas i pieniądze wracały do bibliotek, na których stoi reszta ekosystemu.
