20 mar 2025
17 min

Dlaczego przenieśliśmy naszego bloga z WordPressa na Angulara

Od WordPressa do Angulera: Nasza Migracja

W tym artykule zapraszamy Was do wspólnej podróży transformacji. Dzielimy się doświadczeniami z migracji naszego bloga z WordPressa do architektury headless opartej na Angularze. Powodzenie tego procesu było pełne wyzwań, odkryć i mnóstwa momentów nauki. Bez względu na to, czy jesteś doświadczonym deweloperem, czy dopiero zaczynasz swoją przygodę, mamy nadzieję, że nasza historia zainspiruje Cię do poszukiwania nowych rozwiązań, kwestionowania statusu quo i ciągłego dążenia do doskonałości w swoich projektach. Przeczytaj, podziel się swoimi przemyśleniami i budujmy razem lepsze cyfrowe doświadczenia!

Dlaczego angular.love nie jest zbudowany w Angularze?

To pytanie słyszeliśmy niezliczoną ilość razy. Odpowiedź zazwyczaj była prosta – taka jak większość z Was prawdopodobnie zakłada – „bo działa”. Jednak to do końca była prawda.

Od samego początku angular.love był zarządzany za pomocą WordPressa. Kiedy słyszę „WordPress”, od razu myślę o PHP – języku, który przywołuje wspomnienia z moich mroczniejszych dni pracy z nim. Wierzę, że wiele osób w społeczności niesprawiedliwie odrzuca PHP, często opierając swoje opinie na memach, a nie bezpośrednim doświadczeniu. W rzeczywistości PHP to solidny język dla web developmentu, a WordPress pozwala nam zbudować stronę internetową z minimalnym wysiłkiem – nawet bez zaawansowanych umiejętności programowania.

Z wielką mocą wiąże się wielka odpowiedzialność

WordPress oferuje wszystko, czego potrzebujesz do zbudowania prostej strony, sklepu e-commerce, bloga, a nawet złożonej aplikacji webowej. Możesz znaleźć wtyczki dla prawie każdej funkcjonalności, jaką tylko można sobie wyobrazić. Niestety, im więcej wtyczek instalujesz, tym trudniej nimi zarządzać. Zależności między wtyczkami mogą czasami zepsuć całą stronę, zmuszając Cię do zainstalowania kolejnej wtyczki, aby naprawić problemy spowodowane przez inną. W końcu możesz skończyć się z toną aktywnych wtyczek – niektóre zbędne, inne prawie nieużywane. Dezaktywacja ich może być ryzykowna, ponieważ trudno przewidzieć, co może się zepsuć. Dokładnie te same problemy zidentyfikowaliśmy na naszym blogu.

Rozwijamy się z każdym miesiącem. Angular.love rozpoczął swoją działalność w 2016 roku jako blog skierowany tylko do polskiej publiczności. W 2020 roku zaczęliśmy publikować artykuły w języku angielskim i od tego czasu nasz blog rozrósł się z lokalnej polskiej platformy do globalnej.


Obecnie mamy gości z krajów takich jak Niemcy, Francja, Wielka Brytania, USA, Brazylia, Indie i wiele innych. Wraz z rozwojem naszej społeczności, powinien rozwijać się także nasz blog. Naszym celem jest, aby nasz blog był solidną, przyjazną dla użytkownika aplikacją – charakteryzującą się wysoką wydajnością, doskonałym UX i profesjonalnymi treściami. Obecnie, tylko nasze treści spełniają ten standard, dlatego zdecydowaliśmy się przebudować frontend, zachowując WordPressa jako headless CMS.

Blog angular.love zawsze był tworzony przez deweloperów, dla deweloperów.

Pomysł

Pomysł narodził się w Belgradzie 2 listopada 2023 roku – zaledwie dwa dni przed Angular Belgrade Day. Po długim dniu zwiedzania miasta, trzech utalentowanych deweloperów – Dominik Donoch, Mateusz Stefańczyk i Mateusz Dobrowolski – zdecydowali się na spontaniczny hackathon. W końcu, czyż nie to robią programiści? Tego samego dnia, pierwszy commit trafił na main brancha.
Spędziliśmy godziny na burzę mózgów dyskutując, jak na nowo wymyślić naszego bloga. Choć naszych pomysłów było wiele, były one bardziej eksperymentalne niż konkretne. Szybko zdaliśmy sobie sprawę, że aby naprawdę odnowić naszego bloga, potrzebujemy jasnych wymagań, solidnego planu, przemyślanego projektu i dodatkowych zasobów.


Po powrocie do Polski postanowiliśmy zamienić nasz eksperyment w poważny projekt. Po kilku miesiącach starannych przygotowań, oficjalnie wystartowaliśmy z projektem w kwietniu 2024 roku.

Cel

Wyznaczyliśmy sobie ambitne cele, aby podnieść zarówno wydajność, jak i doświadczenie użytkownika na angular.love. Oto co zamierzamy osiągnąć:

  • Usprawnione wtyczki: Zredukować liczbę zainstalowanych wtyczek do absolutnego minimum, co ograniczy potencjalne konflikty i nakłady na konserwację.
  • Błyskawiczna wydajność: Zwiększyć naszą globalną prędkość ładowania i zbliżyć wyniki Core Web Vitals do 100 w każdej kategorii, zapewniając płynne i responsywne wrażenia użytkownikom na całym świecie.
  • Ulepszone SEO: Poprawić naszą wydajność SEO, aby wyszukiwarki mogły efektywniej indeksować nasz blog, zwiększając naszą widoczność i zasięg.
  • Dopracowana czytelność: Ulepszyć nasz projekt i układ treści, aby nadać blogowi czysty, profesjonalny wygląd, który odzwierciedla jakość naszych artykułów.
  • Accessibility: Wprowadzić kompleksowe funkcje dostępności, aby pomóc użytkownikom z niepełnosprawnościami cieszyć się naszymi treściami bez barier.

Jesteśmy podekscytowani tymi ulepszeniami i przekonani, że stworzą one jeszcze bardziej angażujące i przyjazne dla użytkownika doświadczenie dla naszej rosnącej społeczności.

Dlaczego więc Angular?

Istnieje wiele frameworków, które z łatwością poradziłyby sobie z prostym blogiem – Qwik, NextJS, Nuxt, Astro, SolidStart i wiele innych. Każdy z nich jest doskonałym wyborem, ale wybraliśmy Angular głównie dlatego, że jest naszą najmocniejszą stroną. Ponadto chcieliśmy pokazać, że Angular to nie tylko rozwiązanie dla aplikacji korporacyjnych – to także świetne rozwiązanie dla mniejszych projektów, takich jak blog.

Od Angulara 14, framework przeszedł szereg ekscytujących ulepszeń, które sprawiają, że budowanie szybkich, solidnych aplikacji jest jeszcze bardziej wydajne. Oto niektóre z kluczowych ulepszeń:

  • Standalone Components: Wprowadzone w Angularze 14, pozwalają nam budować komponenty bez tradycyjnych modułów.
  • Hydracja: to proces przywracania renderowanej po stronie serwera aplikacji na kliencie. Obejmuje m.in. ponowne wykorzystanie struktury DOM, zachowanie stanu aplikacji, transfer danych pobranych przez serwer i inne działania.
  • Signals: Nowy, reaktywny model zarządzania stanem wprowadzony w Angularze 16, który upraszcza reaktywność.
  • Deferrable Views: Umożliwiają opóźnione renderowanie części interfejsu użytkownika w celu optymalizacji czasu ładowania.
  • Zoneless Change Detection: Oferuje alternatywę dla tradycyjnego mechanizmu opartego na zone’ach, dodatkowo zwiększając wydajność.
  • … i wiele więcej!

Te funkcje nie tylko pozwalają nam budować aplikacje szybciej i wydajniej, ale także pokazują wszechstronność i ciągłą ewolucję Angulara.

WordPress APIs

Domyślnie WordPress udostępnia dobrze udokumentowane REST API z dużą ilością zasobów, które ułatwia nam transformację. Istnieje jednak kilka zastrzeżeń. Endpointy zwracają pełny schemat, w tym wiele właściwości, których możesz nie potrzebować, co może skutkować niepotrzebnie dużymi odpowiedziami i negatywnie wpłynąć na wydajność. Aby to złagodzić, możemy użyć parametru _fields, aby zażądać tylko danych, które są używane.

Inną kwestią jest to, że REST API jest zaprojektowane z jednym endpointem na zasób. Jeśli Twoja strona wyświetla dane autora, kategorii i artykułu, musimy pobrać każdy zasób osobno. Chociaż ta konfiguracja jest w jakimś stopniu zarządzalna, zastanawialiśmy się, czy można je skonsolidować w jednym request’cie. Jedynym rozwiązaniem na tamten czas było własne rozszerzenie REST API za pomocą dostępnych narzędzi. To dało nam do myślenia – może GraphQL mógłby nam pomóc? Czy WordPress oferuje GraphQL? Brzmi jak idealne rozwiązanie!

Zimny prysznic

Odkryliśmy WPGraphQL – wtyczkę, która udostępnia interfejs API GraphQL dla WordPressa. Dzięki niemu możesz zdefiniować zapytanie po stronie klienta, które żąda tylko pól potrzebnych do konkretnego widoku, a serwer odpowiada tylko tymi danymi. To brzmiało idealnie – dopóki nie zagłębiliśmy się trochę bardziej.

Nasza konfiguracja WordPressa w dużej mierze opierała się na dwóch wtyczkach:

  • ACF: dodaje nowe niestandardowe pola do wbudowanych encji WordPressa.
  • Polylang: obsługa wielojęzycznych tłumaczeń.

Domyślnie WPGraphQL zarządza tylko podstawowym schematem WordPressa. Aby rozszerzyć go o obsługę naszych wtyczek, musieliśmy zainstalować określone integracje: WPGraphQL Polylang i WPGraphQL dla ACF. Ta sytuacja wydawała się kontraproduktywna – instalowanie jednej wtyczki po drugiej, aby osiągnąć efekt docelowy. Zamiast upraszcać naszą konfigurację, wylądowaliśmy z jeszcze większą liczbą wtyczek niż wcześniej.

Następnie chcieliśmy ustanowić jasne kontrakty danych między naszym interfejsem użytkownika i backendem, aby upewnić się, że widoki są renderowane poprawnie. W trakcie tego procesu odkryliśmy, że brakuje nam informacji o tagach meta dostarczonych przez wtyczkę Yoast. Naturalnie, oznaczało to dodanie kolejnej wtyczki integracyjnej – WPGraphQL Yoast SEO.

W tym momencie stało się jasne: im więcej wtyczek integracyjnych dodawaliśmy, tym mniej elastyczny stawał się nasz system. Na przykład, przejście z Yoast na Rank Math wymagałoby znalezienia innej wtyczki integracji GraphQL, co dodawałoby dodatkowy czas i złożoność rozwoju. Ta realizacja zmusiła nas do całkowitego porzucenia tego pomysłu.

WP Rest API

Ostatecznie wróciliśmy do naszego początkowego pomysłu: używania oficjalnego WordPress REST API. A co z wtyczkami, które sprawiały nam problemy z GraphQL? Nasze badania wykazały, że większość naszych wtyczek oferuje natywną integrację z WP REST API – co jest świetną wiadomością, więc zdecydowaliśmy się zbadać to dalej.

Spójrzmy na przykładową porcję danych dla artykułu, zwracanych przez REST API :

{
  "title": {
    "rendered": "Article"
  },
  "content": {
    "rendered": "<!-- HTML Content -->"
  }
}

Teraz porównaj to z tym, jak treść jest renderowana w WordPressie:

A tak wygląda content w odpowiedzi API:

<span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"urvanov-syntax-highlighter-67c8c8aa4e5e8695884298"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"urvanov-syntax-highlighter-syntax crayon-theme-classic urvanov-syntax-highlighter-font-monaco urvanov-syntax-highlighter-os-mac print-yes notranslate"</span> <span class="hljs-attr">data-settings</span>=<span class="hljs-string">" minimize scroll-mouseover"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"margin-top: 12px; margin-bottom: 12px; font-size: 12px !important; line-height: 15px !important; height: auto;"</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-toolbar"</span> <span class="hljs-attr">data-settings</span>=<span class="hljs-string">" mouseover overlay hide delay"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 12px !important; height: 18px !important; line-height: 18px !important; margin-top: -19px; z-index: 4; display: none;"</span>><<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-title"</span>></<span class="hljs-name">span</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-tools"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"font-size: 12px !important;height: 18px !important; line-height: 18px !important;"</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-button urvanov-syntax-highlighter-nums-button crayon-pressed"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Toggle Line Numbers"</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"urvanov-syntax-highlighter-button-icon"</span>></<span class="hljs-name">div</span>></<span class="hljs-name">div</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-button urvanov-syntax-highlighter-plain-button"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Toggle Plain Code"</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"urvanov-syntax-highlighter-button-icon"</span>></<span class="hljs-name">div</span>></<span class="hljs-name">div</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-button urvanov-syntax-highlighter-wrap-button"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Toggle Line Wrap"</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"urvanov-syntax-highlighter-button-icon"</span>></<span class="hljs-name">div</span>></<span class="hljs-name">div</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-button urvanov-syntax-highlighter-expand-button"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Expand Code"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"display: none;"</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"urvanov-syntax-highlighter-button-icon"</span>></<span class="hljs-name">div</span>></<span class="hljs-name">div</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-button urvanov-syntax-highlighter-copy-button"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Copy"</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"urvanov-syntax-highlighter-button-icon"</span>></<span class="hljs-name">div</span>></<span class="hljs-name">div</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-button urvanov-syntax-highlighter-popup-button"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Open Code In New Window"</span>><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"urvanov-syntax-highlighter-button-icon"</span>></<span class="hljs-name">div</span>></<span class="hljs-name">div</span>><<span class="hljs-name">span</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"crayon-language"</span>></span>JavaScript<span class="hljs-tag"></<span class="hljs-name">span</span>></<span class="hljs-name">div</span>></<span class="hljs-name">div</span>></span>
<span class="hljs-tag"><!-- I wiele więcej!!! --></span>

Rany, to całkiem sporo! Do podświetlania fragmentów kodu używaliśmy wtyczki o nazwie Crayon Syntax Highlighter – dosyć starego rozszerzenia włączonego od wczesnych dni powstawania bloga. Nawet jeśli próbowalibyśmy wyrenderować content bezpośrednio z odpowiedzi, nie działało to poprawnie, ponieważ kod ten jest zależny od skryptów Crayona.

Jak więc możemy to obsłużyć? Jedną z opcji jest oczyszczenie danych wyjściowych poprzez wyodrębnienie tylko surowych linii kodu, a następnie zastosowanie podświetlania składni za pomocą biblioteki takiej jak PrismJS lub highlight.js. Niestety, PrismJS wymaga jawnego określenia języka – a każdy fragment kodu w naszej bazie został zapisany jako „JavaScript”, nawet jeśli nie było to poprawne. Z jakiegoś niewytłumaczalnego powodu, ta konfiguracja działała dobrze dla fragmentów nie-JS w WordPressie. Z drugiej strony, highlight.js oferuje API highlightAuto, które automatycznie wykrywa język. To rozwiązanie pasowało idealnie do naszych potrzeb, nawet jeśli dodaje pewien narzut obliczeniowy po stronie klienta. Pozostaje pytanie: czy chcemy obciążać użytkownika tym kosztem?

Dodatkowo, musieliśmy zająć się naszym wcześniejszym problemem dotyczącym wielu żądań API. Oba te wyzwania wydają się idealnymi kandydatami do podejścia BFF (Backend for Frontend). Tworząc dodatkową warstwę między klientem a serwerem, możemy ukryć szczegóły implementacyjne i usprawnić przepływ danych. Nie będziemy zagłębiać się w szczegóły, ale jeśli chcesz dowiedzieć się więcej o tym wzorcu, gorąco polecam zapoznać się z artykułem Mateusza.

BFF: Backend for Frontend – Wyjaśnienie

Potrzebowaliśmy szybkiego serwera NodeJS, który służyłby jako nasze BFF – lekki aktor, który pobiera dane ze źródła, mapuje je, przekazuje do klienta i idealnie jeżeli je cachuje. Wszystko to powinno działać wydajnie w środowiskach serveless i edge.

Na początku NestJS przykuł naszą uwagę. Jest stabilny, szeroko stosowany i współdzieli wiele koncepcji z Angularem, co czyni go naturalnym wyborem, biorąc pod uwagę nasze doświadczenie. Jednak jego pełny narzut frameworka wydawał się przytłaczający dla naszych potrzeb. Potrzebowaliśmy tylko smukłego rozwiązania, więc rozważyliśmy kilka alternatyw:

  • ExpressJS: stary, ale jary.
  • Koa: oferuje prostsze API i lepszą wydajność niż Express, chociaż jego obsługa TypeScript nie jest tak wygodna i wymaga indywidualnego instalowania middleware’ów.
  • Fastify: Bogaty w funkcje i zoptymalizowany pod kątem wydajności, ale zarówno Koa, jak i Fastify w dużej mierze zależą od API Node.js – co sprawia, że ​​są mniej odpowiednie do wypchania go na serverlessa.

Następnie odkryliśmy Hono. Zaprojektowany z minimalnym narzutem i zbudowany w oparciu o Web Standards, Hono jest niezwykle lekki i posiada pierwszorzędną obsługę TypeScript. Jego minimalistyczne API zapewnia o wiele lepsze wrażenia po wyjęciu z pudełka w porównaniu do systemu opartego na wtyczkach Fastify lub podejścia Koa opartego na middleware. Brzmiało idealnie, więc daliśmy mu szanse – i pokochaliśmy go.

Następnie zadaliśmy sobie pytanie: gdzie powinniśmy to hostować? Cloudflare Workers okazało się idealnym kandydatem. Cloudflare Workers to bezserwerowa platforma obliczeniowa, która uruchamia kod zasilany JavaScriptem na edge’u – blisko użytkownika. Dzięki ponad 300+ globalnym lokalizacjom, przetwarza requesty bliżej klienta, znacznie redukując opóźnienia. Niskie opóźnienia, automatyczne skalowanie i brak cold startów sprawiły, że był to idealny wybór dla naszego BFF napędzanego przez Hono. Dodatkowo, jego przyjazny dla deweloperów model cenowy przypieczętował sprawę.

Po wybraniu stacka dla BFF, czas rozpocząć budowę naszej aplikacji frontend!

Nasze decyzje technologiczne

Zaczęliśmy od stworzenia Nx’owego workspace, który pozwala nam na synchronizację udostępnionych elementów – takich jak kontrakty – między frontendem a naszym BFF. Przejdźmy teraz do wyborów bibliotek.

Zarządzanie Stanem

Czy potrzebujemy state managementu? No cóż, tak naprawdę nie… czy jednak? Zdecydowanie nie chcemy ciężkiego globalnego store’a, który wiążę się z dużą ilością boilerplate’u. Wtedy Signal Store, stworzony przez Marko Stanimirovicia, pojawił się jako obiecująca opcja. Jest prosty, wydajny, lekki i wykorzystuje sygnały, dzięki czemu możemy uniknąć zarządzania stanem za pomocą czystego RxJS.

Stylizacja

Jeśli chodzi o frameworki CSS, opcje takie jak Angular Material, Taiga UI lub PrimeNG mogą wydawać się zbyt obszerne dla naszych potrzeb. Zamiast tego, zdecydowaliśmy się na Tailwind CSSa. Jego możliwości szybkiego prototypowania i łatwość użycia (jeśli znasz CSS) sprawiły, że był to naturalny wybór.

Design system

Mimo że nasz projekt jest obszerny, nadal priorytetowo traktowaliśmy inwestowanie czasu w tworzenie dobrze zaprojektowanych, udostępnianych komponentów UI jako części naszego design systemu. Z kilkoma narzędziami na rynku, które odpowiadałyby naszym potrzebom, wybór był jasny – Storybook. Zbudowaliśmy podstawowe historie dla wszystkich kluczowych komponentów, co znacznie ułatwiło ich indywidualne przeglądanie i wizualną ocenę ich wyświetlania i zachowania.

Internacjonalizacja

Ponieważ nasz blog działa zarówno w języku polskim, jak i angielskim, potrzebowaliśmy solidnego rozwiązania do tłumaczeń. Wybraliśmy Transloco – niezwykle popularną i stabilną bibliotekę i18n utrzymywaną przez Netanela Basala w tamtym czasie. Idealnie pasuje do naszych wymagań.

Sekcja komentarzy

Zintegrowanie komentarzy bezpośrednio z WordPressa wymagałoby obsługi autoryzacji użytkownika lub obsługi anonimowych komentarzy, co skomplikowałoby bezpieczeństwo naszego backendu. Zamiast tego, zwróciliśmy uwagę na Giscus. Przy minimalnej konfiguracji, wrzucamy jego web component i voilà – komentarze są załatwione.

Ikony SVG

Stawiliśmy również czoła wyzwaniu optymalnego ładowania ikon SVG. Wtedy @push-based/ngx-fast-svg przyszedł nam z pomocą. Jest wysoce zoptymalizowany i pomógł nam zaoszczędzić cenne punkty w naszych wynikach Core Web Vitals.

@for (item of items(); track $index) {
	<a  
	  role="button"  
	  [attr.aria-label]="t(item.ariaLabel)"  
	  [href]="item.href"  
	  target="_blank"
	>
	  <!-- Optimized SVG loading -->
	  <fast-svg class="text-al-foreground" [name]="item.icon" size="28" />  
	</a>
}

Wyszukiwarka

Użytkownicy oczekują solidnego wyszukiwania, a poleganie na natywnym wyszukiwaniu WordPressa po prostu nie było wydajne. Znaleźliśmy opcje takie jak Algolia, ElasticSearch i Typesense. Ostatecznie model pay-as-you-go Algolii i jego łatwa integracja z WordPress przez wtyczkę WP Search with Algolia sprawiły, że był to idealny wybór.

Skeleton Loaders

Aby jeszcze bardziej poprawić UX, zaimplementowaliśmy skeleton loaders za pomocą biblioteki ngx-skeleton-loader. Ułatwiło to dodanie placeholderów, a sam proces tworzenia jest bajecznie prosty.

Cache

Edge Cloudflare’a to idealne rozwiązanie dla backendu o niskich opóźnieniach – generuje Workera blisko lokalizacji użytkownika końcowego. Niestety nasz VPS znajduje się w Europie. Oznacza to, że nawet jeśli Worker może uruchomić się w pobliżu użytkownika z USA, pobieranie danych z Europy może powodować opóźnienia. Włączenie „Smart Placement” w konfiguracji Workerów pomaga, generując procesor bliżej źródła danych. Niestety, tylko częściowo łagodzi to opóźnienie, ponieważ request nadal musi pokonać połączenie na duże odległości z Europy do USA.

Aby sprostać temu wyzwaniu, wdrożyliśmy mechanizm cache’owania. Zwycięzcą był Cloudflare KV – globalny, niskopoziomowy magazyn typu klucz-wartość, który płynnie integruje się z Workerami. Cloudflare KV służy jako skuteczna warstwa cache’a, pozwalająca nam na szybkie przechowywanie i pobieranie danych z wielu lokalizacji na całym świecie.

Dodatkowo, aby jeszcze bardziej skrócić czas początkowego requesta, włączyliśmy cache’a po stronie REST API WordPressa. Użycie rozszerzenia o nazwie WP REST Cache z bardzo wysokim TTL gwarantowało, że odpowiedzi z naszego CMS były magazynowane na długi czas. Dwuwarstwowa warstwa cache – zarówno na poziomie Workerów, jak i na poziomie API WordPress – znacznie zredukowało ruch w sieci i osiągnęło stale niskie opóźnienia na całym świecie.

W tym momencie nasz przepływ wyglądał następująco:

Wykorzystanie najnowszych funkcji Angulara

Wreszcie, zobowiązaliśmy się do korzystania z najnowszych funkcji w Angularze. Ale jak dokładnie chcemy, żeby to działało? To kolejne wyzwanie, z którym chcemy się zmierzyć.

SPA, SSR czy Pre-rendering?

Zdecydowanie nie Single Page Application – potrzebujemy, aby Google wiedział, co znajduje się na naszym blogu, a SEO jest dla nas krytyczne. Decyzja dotyczyła więc SSR i pre-renderingu. SSR w Angularze wciąż nie ma wielu solidnych funkcji dostępnych w innych meta-frameworkach. Osobiście, z niecierpliwością czekam na rozwój wokół Nitro w obecnej roadmapie. Biorąc jednak pod uwagę nasz obecny stan, musieliśmy wybrać kierunek. Oto nasza analiza:

  • SSR: Server-Side Rendering wymaga hostowania w określonym miejscu i wiąże się z pewnymi problemami z wydajnością. Rozważaliśmy wdrożenie go na Cloudflare Workers, podobnie jak nasze BFF, ale silnik SSR Angulara nie działa od razu po wyjęciu z pudełka – wymaga dodatkowej konfiguracji do uruchomienia w tym środowisku i napotkaliśmy problemy z niektórymi z naszych bibliotek.
  • Pre-rendering: To podejście najzwczajniej generuje statyczne strony, które możemy gdzieś wdrożyć. Brzmi to łatwo, ale oznacza ponowne budowanie całego bloga za każdym razem, gdy następuje zmiana w WordPressie.

Który kierunek wybraliśmy? Ponieważ już korzystamy z Cloudflare, zdecydowaliśmy się wypróbować Cloudflare Pages dla podejścia z pre-renderingiem. Proces przebiegł gładko: z łatwością podłączyliśmy bota Cloudflare do naszego repozytorium w celu automatyzacji deploymentów. Konfiguracja była bardzo prosta – wystarczyło tylko podanie komendy do budowania, ścieżki outputu i wersji Node. Pages obsługuje nawet wystawianie podglądowych deploymentów, co jest fantastyczne do sprawdzania zmian wizualnych związanych z pull requestami.

Jeśli chodzi o prędkość budowania, w tamtym czasie mieliśmy ponad 300 artykułów i około 50 autorów – na oko 400 statycznych stron. Czas budowania był akceptowalny, wahał się od 2 do 5 minut. Postawiliśmy więc na to podejście. Chociaż jest to coś, do czego na pewno wrócimy w przyszłości, na razie jesteśmy zadowoleni z tego rozwiązania.

Nie spoczywamy na laurach

Nasz nowy blog został uruchomiony 12 lipca 2024 roku. Od tego czasu ulepszyliśmy nasz blog jeszcze bardziej. Na przykład, przenieśliśmy nasze fragmenty kodu z highlight.js do Shiki, nowoczesnego narzędzia, które daje nam dodatkową elastyczność i poprawia czytelność kodu.

Kod źródłowy naszego bloga jest publicznie dostępny na GitHubie, co oznacza, że ​​każdy może wnieść swój wkład. Z zadowoleniem przyjmujemy opinie naszych czytelników i zawsze dodajemy nowe funkcje, aby ulepszyć Angular.love. Na koniec, składam specjalne podziękowania dla wszystkich współtwórców, którzy byli częścią tej podróży.

Podziel się artykułem

Zapisz się na nasz newsletter

Dołącz do community Angular.love i bądź na bieżąco z trendami.