Reaktywne mikrofrontendy z Webpack Module Federation
Zastąp rozwiązania workaround dla iframe Webpack 5 Module Federation, aby aplikacje React zarówno lokalne, jak i zdalne mogły dzielić się tym samym środowiskiem wykonawczym, być wdrażane niezależnie, a jednocześnie wyglądać jak jeden produkt.
Duże powierzchnie produktu rzadko stanowią już jeden frontend. Proces zakupów, panele sterowania, ustawienia oraz elementy otaczające je często należą do różnych zespołów, z których każdy ma swój własny backlog, zadłużenie technologiczne oraz harmonogram wypuszczania funkcji. Taka struktura jest zwykle nazywana micro-frontendami: niezależnie zarządzanymi fragmentami interfejsu użytkownika, które mimo to prezentują się jako jeden produkt – to jest kliencka wersja mikrosług.
Przez długi czas narzędzia React do realizacji tego wzorca były niewygodne w użyciu. Organizacje albo używały jednego ogromnego pliku SPA, albo wstawiały oddzielne aplikacje w iframach, akceptując towarzyszące temu koszty. Module Federation w Webpack 5 umożliwił trzecią drogę: niezależnie budowane i wdrażane aplikacje JavaScript, które w czasie wykonywania łączą się w jednym dokumencie przeglądarki. Zrozumienie, co robi ta funkcja – oraz dlaczego zastąpiła starsze rozwiązania – jest istotne dla każdego, kto projektuje systemy React oparte na wielu zespołach.
Problem przed Module Federation
Zanim pojawiła się Federation, zespoły chcące niezależnej dystrybucji interfejsu użytkownika miały ograniczone możliwości wyboru.
Domyślnym rozwiązaniem był monolityczny SPA: jeden repozytorium, jedna ścieżka przetwarzania, jedno wdrożenie. Taki model nadaje się dla małej grupy. Gdy odpowiedzialność rozprzestrzenia się, pojawiają się trudności. Każda funkcja korzysta z tego samego buildu. Czas kompilacji rośnie wraz z rozmiarem bazy kodu. Regresja w jednej dziedzinie może sparaliżować proces wdrażania innego zespołu. Ujednolicenie wdrożeń pomiędzy wieloma grupami staje się samodzielnym zadaniem z zakresu zarządzania projektem.
Innym powszechnie stosowanym rozwiązaniem były iframy. Wbudowanie pełnej aplikacji potomnej w stronę nadrzędną zapewniało prawdziwą niezależność wdrożeń, dlatego tak wiele przedsiębiorstw ich używało. Wady tego podejścia szybko się kumulowały:
- Izolacja jest absolutna. Konteksty stylów, DOM i JavaScript nie mieszają się ze sobą. Dzielenie się stanem, koordynacja danych lub narzucanie jednego języka projektowego w kontekście elementów rodzicielskich i potomnych staje się trudnym zadaniem inżynieryjnym zamiast zwykłego przekazywania właściwości.
- Zależności się powtarzają. Każda karta często ładuje swój własny React, biblioteki współdzielone oraz CSS. Użytkownicy wielokrotnie pobierają te same dane.
- UX ulega pogorszeniu. Przewijanie, fokusowanie, zmiana rozmiaru, łącza głębokie oraz funkcje historii pomiędzy kartami wymagają specjalnych rozwiązań i nadal sprawiają problemy.
- SEO i dostępność ulegają pogorszeniu. Treść w kartach jest trudniejsza do indeksowania i mniej spójna dla technologii wspomagających.
- Komunikacja odbywa się wyłącznie poprzez wiadomości. Przekazywanie danych między kartami odbywa się za pomocą
postMessageoraz ręcznie opracowanych protokołów — bez wspólnej pamięci, bez wspólnego kontekstu React.
Iframe’y rozwiązały problem wysyłania niezależnie, ale stworzyły gorszy problem czystej integracji. Brakowało niezależności podczas budowania i wdrażania bez rezygnacji z doświadczenia użytkownika opartego na jednym dokumencie.
Czym jest Module Federation?
Module Federation, wprowadzony wraz z Webpack 5, umożliwia aplikacjom JavaScript budowanym i wdrażanym oddzielnie dzielenie się kodem w czasie wykonywania, a nie w czasie kompilacji.
W praktyce można uruchamiać kilka aplikacji – pochodzących od różnych zespołów, procesów i wersji – które mimo to łączą się w przeglądarce w jeden produkt. Jedna aplikacja udostępnia komponent, trasę lub narzędzie pomocnicze; druga korzysta z nich tak, jakby znajdowały się w tym samym pakiecie, bez konieczności ponownego budowania aplikacji konsumenta w momencie zmiany dostawcy.
Taka kompozycja w czasie wykonywania stanowi obecnie podstawę techniczną mikrofrontendów w React.
Jak to działa: hosty, zdalne serwery i wspólne zależności
Federacja wyróżnia dwa role:
- Host ładuje kod opublikowany w innym miejscu. Często jest to środowisko, które montuje interfejs użytkownika innych zespołów.
- Zdalny serwer publikuje moduły dla innych: strony, komponenty, hooki lub narzędzia.
Jedna aplikacja może pełnić obie role: udostępniać niektóre moduły, jednocześnie korzystając z innych.
Zdalne serwery deklarują elementy do eksportu w konfiguracji Webpacka; hosty określają, które zdalne serwery mają być załadowane oraz jakie symbole mają zostać sprowadzone. Ładowanie odbywa się w przeglądarce pod adresem wejściowym zdalnego serwera. Budowa hosta nie wymaga źródła kodu zdalnego serwera – wystarczy stabilny punkt wejścia, który może zostać pobraany podczas uruchamiania aplikacji.
Wspólne zależności dopełniają obraz sytuacji. Gdy zarówno host, jak i serwer zdalny potrzebują Reacta, można poinstruować Federation o udostępnieniu jednej instancji Reacta zamiast wysyłania dwóch. Dzięki temu eliminuje się duplikację w stylu iframe, a jednocześnie zespoły mogą stosować różne wersje, gdy jest to konieczne.
Federation modułów vs. Iframes
To właśnie ta różnica sprawiła, że tak wiele zespołów porzuciło iframes po udoskonaleniu Federation. Zachowuje się niezależność wdrożeń, która sprawiała, że iframes były atrakcyjne, bez rezygnacji z jakości integracji. Serwery zdalne integrują się z DOM hosta, dzielą jeden świat JavaScripta i mogą ponownie wykorzystywać dostawców, stan oraz pakiety systemu projektowego – co wcześniej było trudne lub niemożliwe przy użyciu iframes.
Dlaczego używają tego duże zespoły
Małe produkty rzadko potrzebują takich rozwiązań. Organizacje z wieloma zespołami front-endu korzystają z Federation, aby rozwiązać strukturalne problemy:
- Niezależne wdrażanie. Zespół zdalny może wprowadzić poprawkę bez konieczności przekompilowywania artefaktów wszystkich innych zespołów.
- Autonomia zespołów. Każda grupa decyduje o własnym tempie pracy, narzędziach CI oraz, w określonych granicach, wyborze narzędzi.
- Szybsza kompilacja. Oddzielne zespoły zdalne oznaczają, że mała zmiana nie wymusza przekompilowania całego systemu monolitycznego.
- Krokowa modernizacja. Stare struktury mogą stopniowo dodawać nowe zespoły zdalne, zamiast przeprowadzać jednorazową zmianę.
- Elastyczność stacku technologicznego. Najprościej jest dzielić się jednym frameworkiem, ale zespoły czasami łączą różne wersje lub nawet różne frameworki poprzez mechanizmy Federacji.
Przykłady zastosowań w praktyce
Strony e-commerce często pozwalają zespołom odpowiedzialnym za katalog, proces zakupów oraz konta korzystać z oddzielnych narzędzi zdalnego zarządzania. Produkty typu SaaS dostarczają elementy interfejsu lub panele ustawień od zespołów zajmujących się funkcjonalnościami, bez konieczności otwierania głównej struktury aplikacji przy każdej zmianie. Procesy migracji pozwalają oddzielać poszczególne części starej aplikacji SPA i przenosić je do oddzielnych narzędzi, podczas gdy stara wersja nadal działa.
Podsumowanie głównych zalet
Wartości federacji można streścić w krótkiej liście: prawdziwa możliwość niezależnego wdrażania, wspólny środowisko działania zapobiegające duplikacji bibliotek oraz niestabilnej komunikacji między aplikacjami, a także doświadczenie użytkownika przypominające korzystanie z jednej aplikacji. Zapewnia to obiecaną autonomię bez konsekwencji związanych z integracją i spadkiem wydajności.
Wniosek
Przejście od iframów do Module Federation jest częścią szerszego rozwoju architektury frontendu: niezależność wdrożeń oraz spójna obsługa użytkownika nie muszą już być przeciwieństwami. Webpack 5 umożliwił taką kombinację organizacjom intensywnie korzystającym z Reacta, które przerosły możliwości pojedynczego pliku pakietowego. W miarę wzrostu zastosowań oraz gdy narzędzia takie jak Rspack i Module Federation 2.0 rozwijają te same koncepcje współdzielenia środowiska wykonawczego, zrozumienie przyczyn tej zmiany pomaga każdemu projektującemu duże systemy Reactowe świadomie określać granice odpowiedzialności, zamiast polegać na iframach lub coraz większych monolitach.
Spróbuj sam
Minimalny przykład hosta/odległego serwera jest dostępny pod adresem react_module_federation.
Klonuj go lokalnie:
git clone https://github.com/ModithaM/react_module_federation.git
cd react_module_federation
Najpierw uruchom odległy serwer, aby jego dostępna ścieżka wejściowa była aktywna, zanim host poprosi o moduły:
cd remote
npm install
npm start
W drugim terminalu uruchom hosta:
cd host
npm install
npm start
Otwórz hosta w przeglądarce; powinien on ładować zdalne komponenty w czasie wykonywania i pokazywać opisany powyżej związek. Kolejność ma znaczenie: host uruchomiony samodzielnie nie ma nic do pobrania, dopóki zdalny serwer nie będzie dostępny, co stanowi przydatne przypomnienie, że niezależność Federation nadal zależy od dostępności serwerów zdalnych podczas uruchamiania shella.
Literatura pokrewna
- Self-adaptive JavaScript frontends dla interfejsów napędzanych AI — Jak strumieniowanie, wyszukiwanie wektorów, reaktywny stan, dynamiczne komponenty oraz możliwość obserwacji przekształcają architekturę klienta w interfejsach typu UI opartych na AI.