Micro Frontends

rozszerzenie idei mikroserwisu na frontend

Zobacz projekt na GitHub
EN JP ES PT KR RU CN IT PL

Techniki, strategie i receptury budowy nowoczesnych aplikacji web przez wiele zespołów, które mogą dostarczać funkcjonalnosci niezależnie.

Czym są Micro Frontends?

Termin Micro Frontends po raz pierwszy pojawił się w ThoughtWorks Technology Radar pod koniec 2016 roku. Rozszerza koncepcje mikrousług na świat frontendu. Zgodnie z obecnym trendem budujemy bogate w funkcje i wydajne aplikacje web, zwane również aplikacjami jednostronicowymi (SPA), które odwołuja się do mikrousług. Z biegiem czasu warstwa frontendowa, często rozwijana przez osobny zespół, rozrasta się i staje się trudniejsza w utrzymaniu. Nazywamy to monolitem frontendowym.

Ideą Micro Frontends jest myślenie o aplikacji web jako o kompozycji funkcjonalności, które są własnością niezależnych zespołów. Każdy zespół ma odrębną dziedzinę działalności lub misję, o którą się troszczy i w której się specjalizuje. Zespół jest interdyscyplinarny i rozwija swoje funkcje od początku do końca, od bazy danych po interfejs użytkownika.

Pomysł ten nie jest jednak nowy. Ma wiele wspólnego z koncepcją Self-contained Systems. W przeszłości takie podejście nosiło nazwę Frontend Integration for Verticalised Systems. Micro Frontends jest dużo bardziej przyjaznym i poręcznym terminem.

Monolithic Frontends Monolithic Frontends

Organisation in Verticals Zespoły z Micro Frontends

Czym jest nowoczesna aplikacja web?

We wstępie użyłem sformułowania „budowa nowoczesnych aplikacji web”. Zdefiniujmy założenia, które wiążą się z tym terminem.

Aby spojrzeć na to z szerszej perspektywy, Aral Balkan napisał post na blogu o tym, co nazywa Documents‐to‐Applications Continuum. Wymyśla koncepcję osi, w której witryna zbudowana ze statycznych dokumentów połączonych linkami znajduje się po lewej stronie, a w pełni zorientowana na zachowania, aplikacja bez treści, jak internetowy edytor zdjęć, znajduje się po prawej.

Jeśli umieścisz swój projekt po lewej stronie tego spektrum, dobrym wyborem będzie integracja na poziomie serwera WWW. W tym modelu serwer zbiera i łączy ciągi znaków HTML ze wszystkich komponentów składających się na żądaną przez użytkownika stronę. Aktualizacje odbywają się poprzez przeładowanie strony z serwera lub wymianę jej części przez ajax. Gustaf Nilsson Kotte napisał obszerny artykuł na ten temat.

Gdy interfejs użytkownika musi zapewniać natychmiastową informację zwrotną, nawet w przypadku zawodnych połączeń, witryna renderowana wyłącznie przez serwer nie będzie już wystarczająca. Chcąc wdrożyć techniki, takie jak Optimistic UI lub Skeleton Screens musisz mieć możliwość aktualizacji swojego interfejsu użytkownika na samym urządzeniu. Termin Google Progressive Web Apps trafnie opisuje balansowanie pomiędzy byciem dobrym obywatelem sieci (progresywne ulepszanie), a jednocześnie zapewnieniem wydajnosci podobnej do aplikacji. Ten rodzaj aplikacji znajduje się gdzieś mniej więcej po środku kontinuum witryna-aplikacja. Tutaj rozwiązanie oparte wyłącznie na serwerze nie jest już wystarczające i musimy przenieść integrację do przeglądarki. To właśnie jest tematem niniejszego artykułu.

Podstawowe idee kryjące się za Micro Frontends

  • Bądź niezależny od technologii
    Każdy zespół powinien mieć możliwość wyboru i ulepszenia swojego stosu bez konieczności koordynacji z innymi zespołami. Custom Elements to świetny sposób na ukrycie szczegółów implementacji, zapewniając jednocześnie neutralny interfejs innym.
  • Izoluj kod zespołu
    Nie udostępniaj środowiska uruchomieniowego, nawet jeśli wszystkie zespoły używają tego samego frameworka. Twórz niezależne aplikacje, które są samowystarczalne. Nie polegaj na wspólnych stanach ani zmiennych globalnych.
  • Ustal prefiksy zespołów
    Uzgodnij konwencje nazewnictwa tam, gdzie izolacja nie jest jeszcze możliwa. Użyj przestrzeni nazw dla CSS, zdarzeń, Local Storage i ciastek w celu uniknięcia kolizji i pokazania własności.
  • Preferuj natywne funkcje przeglądarki zamiast niestandardowych API
    Używaj Zdarzeń przeglądarki do komunikacji zamiast budować globalny system PubSub. Jeśli naprawdę musisz zbudować międzyzespołowe API, postaraj się, aby było to jak najprostsze.
  • Zbuduj elastyczną witrynę
    Twoja funkcja powinna być użyteczna, nawet jeśli JavaScript nie zadziałał lub nie został jeszcze uruchomiony. Użyj Universal Rendering i Progressive Enhancement, aby poprawić postrzeganą wydajność.

DOM jest API

Custom Elements, czyli aspekt interoperacyjności ze specyfikacji Web Components, jest dobrą podstawą do integracji w przeglądarce. Każdy zespół buduje swój komponent przy użyciu wybranej przez siebie technologii i opakowuje go w Custom Element (np. <order-minicart></order-minicart>). Specyfikacja DOM tego konkretnego elementu (nazwa tagu, atrybuty i zdarzenia) działa jak kontrakt lub publiczne API dla innych zespołów. Zaletą jest to, że mogą korzystać z komponentu i jego funkcjonalności bez znajomości implementacji. Muszą jedynie mieć możliwość interakcji z DOM.

Jednak same Custom Elements nie są rozwiązaniem dla wszystkich naszych potrzeb. Aby mówić o progresywnym ulepszaniu, uniwersalnym renderowaniu czy routingu, potrzebujemy dodatkowego oprogramowania.

Ta strona jest podzielona na dwa główne obszary. Najpierw omówimy Kompozycję strony — jak złożyć stronę z komponentów należących do różnych zespołów. Następnie pokażemy przykłady implementacji przejść pomiędzy stronami po stronie klienta.

Kompozycja strony

Poza samą integracją kodu po stronie klienta i serwera napianego w różnych frameworkach, istnieje wiele pobocznych tematów, które należy omówić: mechanizmy izolowania js, unikanie konfliktów css, ładowanie zasobów w razie potrzeby, dzielenie wspólnych zasobów między zespołami, pobieranie danych i dobrej prezentacji wskaźników ładowania dla użytkownika. Zajmiemy się tymi tematami krok po kroku.

Prototyp

Jako podstawa dla poniższych przykładów posłuży nam strona produktu sklepu z traktorami.

Na stronie jest selektor modelu do przełączania między trzema różnymi modelami traktorów. Po zmianie obraz produktu, aktualizowane są nazwa, cena i rekomendacje. Dostępny jest również przycisk kupowania, który dodaje wybrany model do koszyka, a minikoszyk u góry odpowiednio się aktualizuje.

Przykład 0 — strona produktu — zwykły JS

spróbuj w przeglądarce i sprawdź kod

Cały HTML jest generowany po stronie klienta przy użyciu zwykłego JavaScript i szablonów ES6 z bez zależności. Kod wykorzystuje prostą separację stanu/znaczników i ponownie renderuje całą stronę klienta HTML po każdej zmianie - na razie bez fantazyjnego różnicowania DOM i bez uniwersalnego renderowania. Nie ma też separacji zespołu - kod jest zapisany w jednym pliku js/css.

Integracja po stronie klienta

W tym przykładzie strona jest podzielona na osobne komponenty/fragmenty należące do trzech zespołów. Team Checkout (niebieski) jest teraz odpowiedzialny za wszystko, co dotyczy procesu zakupu, a mianowicie za przycisk kupowania i minikoszyk. Team Inspire (zielony) zarządza rekomendacjami produktów na tej stronie. Sama strona jest własnością Team Product (czerwony).

Przykład 1 - Strona produktu - Skład

spróbuj w przeglądarce i sprawdź kod

Każdy zespół

Team Product decyduje, która funkcjonalność jest uwzględniona i gdzie jest umieszczona na stronie. Strona zawiera informacje, które może dostarczyć sam Team Product, takie jak nazwa produktu, zdjęcie i dostępne modele. Może jednak zawierać również fragmenty (Custom Elements) z innych zespołów.

Jak stworzyć Custom Element?

Weźmy jako przykład przycisk kupowania. Team Product wstawił przycisk po prostu dodając w żądanym miejscu strony <blue-buy sku="t_porsche"></blue-buy>. Aby to zadziałało, Team Checkout musiał zarejestrować element blue-buy na stronie.

class BlueBuy extends HTMLElement {
  connectedCallback() {
    this.innerHTML = `<button type="button">buy for 66,00 €</button>`;
  }

  disconnectedCallback() { ... }
}
window.customElements.define('blue-buy', BlueBuy);

Teraz za każdym razem, gdy przeglądarka napotyka nowy tag blue-buy, wywoływane jest connectedCallback. this jest odniesieniem do głównego węzła DOM Custom Element. Dostępne są wszystkie właściwości i metody standardowego elementu DOM, takich jak innerHTML lub getAttribute().

Custom Element in Action

Podczas nazywania elementu jedynym wymaganiem, jakie określa specyfikacja, jest to, że nazwa musi zawierać myślnik (-), aby zachować zgodność z nadchodzącymi nowymi tagami HTML. W kolejnych przykładach używana jest konwencja nazewnictwa [kolor_zespołu]-[funkcja]. Przestrzeń nazw zespołu chroni przed kolizjami a zarazem zespół będący właścicielem funkcji staje się oczywisty, z samego spojrzenia na DOM.

Komunikacja rodzic-dziecko / Modyfikacja DOM

Gdy użytkownik wybierze inny ciągnik w selektorze modeli, przycisk kupowania musi zostać odpowiednio zaktualizowany. Aby osiągnąć ten produkt zespołowy, wystarczy usunąć istniejący element z DOM i wstawić nowy.

container.innerHTML;
// => <blue-buy sku="t_porsche">...</blue-buy>
container.innerHTML = '<blue-buy sku="t_fendt"></blue-buy>';

Funkcja disconnectedCallback starego elementu jest wywoływana synchronicznie, aby zapewnić elementowi szansę na porządki, takie jak wyczyszczenie podpiętych zdarzeń. Następnie wywoływana jest funkcja connectedCallback nowo utworzonego elementu t_fendt.

Inną, bardziej wydajną opcją jest po prostu aktualizacja atrybutu sku istniejącego elementu.

document.querySelector('blue-buy').setAttribute('sku', 't_fendt');

Gdyby Team Product używał silnika szablonów, który obsługuje różnicowanie DOM, takiego jak React, algorytm zrobiłby to automatycznie.

Custom Element Attribute Change

Aby to obsłużyć Custom Element może zaimplementować funkcję attributeChangedCallback i określić listę observedAttributes, dla których ma zostać wywołana ta funkcja.

const prices = {
  t_porsche: '66,00 €',
  t_fendt: '54,00 €',
  t_eicher: '58,00 €',
};

class BlueBuy extends HTMLElement {
  static get observedAttributes() {
    return ['sku'];
  }
  connectedCallback() {
    this.render();
  }
  render() {
    const sku = this.getAttribute('sku');
    const price = prices[sku];
    this.innerHTML = `<button type="button">buy for ${price}</button>`;
  }
  attributeChangedCallback(attr, oldValue, newValue) {
    this.render();
  }
  disconnectedCallback() {...}
}
window.customElements.define('blue-buy', BlueBuy);

Aby uniknąć powielania kodu, wprowadzono metodę render(), która jest wywoływana z connectedCallback i attributeChangedCallback. Ta metoda zbiera potrzebne dane i ustawia zawartość innerHTML nowego znacznika. Decydując się na bardziej wyrafinowany silnik szablonów lub framework wewnątrz Custom Element, tutaj trafiłby jego kod inicjujący.

Wsparcie w przeglądarkach

W powyższym przykładzie zastosowano specyfikację Custom Element V1, która jest obecnie obsługiwana w przeglądarkach Chrome, Safari i Opera. Ale z document-register-element dostępny jako lekki i przetestowany w boju polyfill, zadziała we wszystkich przeglądarkach. Korzysta on z powszechnie wspieranego Mutation Observer API, więc w tle nie ma podglądania drzewa DOM.

Kompatybilność frameworków

Ponieważ Custom Elements są standardem web, obsługują je wszystkie główne frameworki JavaScript, takie jak Angular, React, Preact, Vue czy Hyperapp. Ale kiedy przejdziesz do szczegółów, nadal istnieje kilka problemów z implementacją w niektórych frameworkach. W Custom Elements Everywhere Rob Dodson przygotował zestaw testów zgodności, który zwraca uwagę na nierozwiązane problemy.

Unikaj anarchii frameworków

Korzystanie z elementów niestandardowych to świetny sposób na osiągnięcie wysokiego stopnia rozdzielenia między fragmentami poszczególnych zespołów. W ten sposób każdy zespół ma swobodę wyboru frameworka frontendowego. Ale to, że możesz, nie oznacza, że ​​mieszanie różnych technologii jest dobrym pomysłem. Staraj się unikać Micro Frontends Anarchy i stwórz rozsądny poziom zgodności między różnymi zespołami. W ten sposób zespoły mogą dzielić się wiedzą i najlepszymi praktykami. Ułatwi Ci to również życie, gdy zechcesz założyć centralną bibliotekę wzorów. To powiedziawszy, możliwość łączenia technologii może być przydatna, gdy pracujesz ze starszą aplikacją i chcesz przeprowadzić migrację do nowego stosu technologicznego.

Komunikacja między dzieckiem a rodzicem lub rodzeństwem / Zdarzenia DOM

Przekazywanie w dół atrybutów nie jest wystarczające dla wszystkich interakcji. W naszym przykładzie minikoszyk powinien się odświeżyć, gdy użytkownik kliknie przycisk kupowania.

Oba fragmenty są własnością Team Checkout (niebieski), więc mogliby zbudować coś w rodzaju wewnętrznego API JavaScript, które poinformuje minikoszyk, kiedy naciśnięto przycisk. Wymagałoby to jednak wzajemnej znajomości instancji komponentów, a także stanowiłoby naruszenie izolacji.

Czystszym sposobem jest użycie mechanizmu PubSub, w którym komponent może publikować wiadomość, a inne komponenty mogą subskrybować określone tematy. Na szczęście przeglądarki mają tę funkcję wbudowaną. Dokładnie w ten sposób działają zdarzenia przeglądarki, takie jak click, select lub mouseover. Oprócz natywnych zdarzeń istnieje również możliwość tworzenia zdarzeń wyższego poziomu za pomocą new CustomEvent(...). Zdarzenia są zawsze powiązane z węzłem DOM, w którym zostały utworzone/wysłane. Większość natywnych zdarzeń obsługuje bąbelkowanie. Umożliwia to nasłuchiwanie wszystkich zdarzeń w określonym poddrzewie DOM. Jeśli chcesz nasłuchiwać wszystkich zdarzeń na stronie, dołącz obsługę zdarzenia do elementu okna. Oto przykład tworzenia zdarzenia blue:basket:changed:

class BlueBuy extends HTMLElement {
  [...]
  connectedCallback() {
    [...]
    this.render();
    this.firstChild.addEventListener('click', this.addToCart);
  }
  addToCart() {
    // maybe talk to an api
    this.dispatchEvent(new CustomEvent('blue:basket:changed', {
      bubbles: true,
    }));
  }
  render() {
    this.innerHTML = `<button type="button">buy</button>`;
  }
  disconnectedCallback() {
    this.firstChild.removeEventListener('click', this.addToCart);
  }
}

Minikoszyk może teraz subskrybować to zdarzenie na elemencie window i otrzymywać powiadomienia, kiedy powinien odświeżyć swoje dane.

class BlueBasket extends HTMLElement {
  connectedCallback() {
    [...]
    window.addEventListener('blue:basket:changed', this.refresh);
  }
  refresh() {
    // fetch new data and render it
  }
  disconnectedCallback() {
    window.removeEventListener('blue:basket:changed', this.refresh);
  }
}

Przy takim podejściu fragment minikoszyka dodaje obsługę zdarzenia do elementu DOM, który jest poza jego zakresem (window). Powinno to być bezpieczne w przypadku wielu aplikacji, ale jeśli nie czujesz się z tym komfortowo, możesz zawsze zastosować podejście, w którym sama strona (Team Product) nasłuchuje zdarzenia i powiadamia minikoszyk, wywołując funkcję refresh() na elemencie DOM.

// page.js
const $ = document.getElementsByTagName;

$('blue-buy')[0].addEventListener('blue:basket:changed', function() {
  $('blue-basket')[0].refresh();
});

Imperatywne wywoływanie metod DOM jest dość rzadkie, ale można je znaleźć na przykład w video element api. Jeśli to możliwe, należy preferować podejście deklaratywne (zmiana atrybutu).

Renderowanie po stronie serwera / Renderowanie uniwersalne

Custom Elements świetnie nadają się do integracji komponentów w przeglądarce. Jednak podczas tworzenia witryny, która jest dostępna w sieci, Ważna jest wydajność. Istnieje duże prawdopodobieństwo, że dopóki wszystkie frameworki js nie zostaną pobrane i uruchomione użytkownicy będą widzieć biały ekran. Dodatkowo dobrze jest pomyśleć o tym, co stanie się z witryną, jeśli JavaScript zawiedzie lub zostanie zablokowany. Wagę tego problemu pokazuje Jeremy Keith w swoim ebooku/podcaście Resilient Web Design. Dlatego możliwość wyrenderowania podstawowej zawartości na serwerze jest kluczowa. Niestety specyfikacja komponentów web w ogóle nie mówi o renderowaniu po stronie serwera. Nie ma JavaScript, nie ma Custom Elements :(

Custom Elements + Server Side Includes = ❤️

W celu uruchomienia renderowania po stronie serwera zrefaktorujemy poprzedni przykład. Każdy zespół ma własny serwer ekspresowy, a metoda render() Custom Element jest również dostępna za pośrednictwem adresu URL.

$ curl http://127.0.0.1:3000/blue-buy?sku=t_porsche
<button type="button">buy for 66,00 €</button>

Nazwa znacznika Custom Element jest używana jako fragment ścieżki - atrybuty stają się parametrami zapytania. Teraz istnieje sposób na renderowanie zawartości każdego komponentu po stronie serwera. W połączeniu z <blue-buy>-Custom Element osiągamy coś, co jest dość bliskie do Universal Web Component:

<blue-buy sku="t_porsche">
  <!--#include virtual="/blue-buy?sku=t_porsche" -->
</blue-buy>

Komentarz #include jest częścią Server Side Includes, która jest funkcją dostępną na większości serwerów WWW. Tak, jest to ta sama technika, której używano kiedyś do umieszczania bieżącej daty na stronach. Istnieje również kilka alternatywnych technik, takich jak ESI, nodesi, compoxure i tailor, ale w naszych projektach SSI sprawdziło się jako proste i niezwykle stabilne rozwiązanie.

Komentarz #include jest zastępowany odpowiedzią /blue-buy?sku=t_porsche zanim serwer WWW wyśle ​​całą stronę do przeglądarki. Konfiguracja w nginx wygląda tak:

upstream team_blue {
  server team_blue:3001;
}
upstream team_green {
  server team_green:3002;
}
upstream team_red {
  server team_red:3003;
}

server {
  listen 3000;
  ssi on;

  location /blue {
    proxy_pass  http://team_blue;
  }
  location /green {
    proxy_pass  http://team_green;
  }
  location /red {
    proxy_pass  http://team_red;
  }
  location / {
    proxy_pass  http://team_red;
  }
}

Dyrektywa ssi: on; włącza funkcję SSI, a bloki upstream i location dla każdego zespołu mają zapewnić, że wszystkie adresy URL zostanąskierowane do właściwej aplikacji (np. /blue do team_blue: 3001). Dodatkowo trasa / jest mapowana do zespołu red, który kontroluje stronę główną/stronę produktu.

Poniższa animacja przedstawia sklep z traktorami w przeglądarce z wyłączoną obsługą JavaScript.

Renderowanie po stronie serwera — wyłączony JavaScript

sprawdź kod

Przyciski wyboru modelu są teraz rzeczywistymi linkami, a każde kliknięcie powoduje przeładowanie strony. Terminal po prawej ilustruje proces routowania zapytania o stronę do zespołu red, który kontroluje stronę produktową, po czym strona jest uzupełniana fragmentami z zespołu blue i green.

Po ponownym włączeniu JavaScript widoczne będą tylko komunikaty dziennika serwera dotyczące pierwszego żądania. Wszystkie kolejne zmiany ciągnika są obsługiwane po stronie klienta, tak jak w pierwszym przykładzie. W późniejszym przykładzie dane produktu zostaną wyodrębnione z kodu JavaScript i w razie potrzeby załadowane przez żądanie REST.

Możesz poeksperymentować z kodem tego przykładu na komputerze lokalnym. Musisz jedynie zainstalować Docker Compose.

git clone https://github.com/neuland/micro-frontends.git
cd micro-frontends/2-composition-universal
docker-compose up --build

Następnie Docker uruchamia nginx na porcie 3000 i buduje obraz node.js dla każdego zespołu. Kiedy otworzysz http://127.0.0.1:3000/ w przeglądarce, powinieneś zobaczyć czerwony traktor. Połączony dziennik docker-compose ułatwia sprawdzenie, co dzieje się w sieci. Niestety nie ma możliwości kontrolowania koloru wyjściowego, więc musisz znieść fakt, że niebieski zespół może być podświetlony na zielono :)

Pliki src są mapowane do poszczególnych kontenerów, a aplikacja węzła przeładuje się po wprowadzeniu zmiany w kodzie. Zmiana nginx.conf wymaga restartu docker-compose, aby odniosła skutek. Więc nie krępuj się bawić i wyrażać opinię.

Ładowanie danych i stany pobierania

Wadą podejścia SSI/ESI jest to, że najwolniejszy fragment określa czas ładowania całej strony. Dobrze zatem, gdy odpowiedź fragmentu może być buforowana. W przypadku fragmentów, które są kosztowne w renderowaniu i trudne do buforowania, często dobrym pomysłem jest wykluczenie ich z początkowego renderowania. Mogą być ładowane asynchronicznie w przeglądarce. W naszym przykładzie fragment green-recos, który pokazuje spersonalizowane rekomendacje jest do tego dobrym kandydatem.

Jednym z możliwych rozwiązań byłoby po prostu pominięcie SSI Include przez zespół czerwony.

Before

<green-recos sku="t_porsche">
  <!--#include virtual="/green-recos?sku=t_porsche" -->
</green-recos>

After

<green-recos sku="t_porsche"></green-recos>

Ważna uwaga dodatkowa: Custom Elements nie mogą być samozamykające się, więc zapis <green-recos sku="t_porsche" /> nie zadziałałby poprawnie.

Reflow

Renderowanie odbywa się tylko w przeglądarce. Jednak, jak widać na animacji, zmiana ta wprowadziła widoczne ponowne formatowanie strony. Obszar poleceń jest początkowo pusty. JavaScript zespołu zielonego jest ładowany i wykonywany. Wykonywane jest żadanie API w celu pobrania spersonalizowanej rekomendacji. Rekomendowany znacznik jest renderowany i pobierane są skojarzone obrazy. Fragment potrzebuje teraz więcej miejsca i rozpycha układ strony.

Istnieją różne opcje, aby uniknąć takiego irytującego rozpychania. Zespół czerwony, który kontroluje stronę, mógłby ustalić wysokość kontenera rekomendacji. Na responsywnej stronie często jednak trudno jest określić wysokość, ponieważ może się różnić dla różnych rozmiarów ekranu. Większym problemem jest jednak to, że taki rodzaj porozumienia między zespołami tworzy ścisłe powiązanie między czerwonymi i zielonymi. Jeśli zespół zielonych chce wprowadzić dodatkowy nagłówek w elemencie rekomendacji, to musi się dogadać z zespołem czerwonych w kwestii nowej wysokości. Oba zespoły musiałyby wprowadzić swoje zmiany jednocześnie, aby uniknąć zepsucia układu.

Lepszym sposobem jest użycie techniki o nazwie Skeleton Screens. Zespół czerwony pozostawia SSI green-recos w szablonie. Zespół zielony zmienia metodę renderowania po stronie serwera swojego fragmentu, tak aby tworzył schematyczną wersję zawartości. znaczniki szkieletu mogą ponownie wykorzystywać części stylów układu rzeczywistej treści. W ten sposób rezerwuje potrzebną przestrzeń, a załadowanie właściwej treści nie prowadzi do przeskoku.

Skeleton Screen

Szkieletowe ekrany są również bardzo przydatne do renderowania po stronie klienta. Kiedy Twój niestandardowy element zostanie wstawiony do DOM w wyniku działania użytkownika, może natychmiast renderować szkielet, dopóki nie dotrą dane, których potrzebuje z serwera.

Nawet przy zmianie atrybutu, jak w przypadku wyboru modelu, możesz chcieć przełączyć się na widok szkieletu, dopóki nie pojawią się nowe dane. W ten sposób użytkownik otrzymuje wskazówkę, że coś się dzieje we fragmencie. Jednak gdy serwer reaguje szybko, krótkie szkieletowe migotanie między starymi a nowymi danymi również może być irytujące. Pomocne może być zachowanie starych danych lub użycie inteligentnych limitów czasu. Więc używaj tej techniki rozsądnie i staraj się uzyskać opinie użytkowników.

Nawigacja pomiędzy stronami

ciąg dalszy nastąpi wkrótce … (obiecuję)

obejrzyj Github Repo, aby otrzymać powiadomienie

Dodatkowe zasoby

Powiązane techniki

Posty: Cookie Cutter Scaling David Hammet napisał serię postów na blogu na ten temat.


Rzeczy, które nadejdą … (wkrótce)

  • Przypadki użycia
    • Nawigacja pomiędzy stronami
      • miękka vs. twarda nawigacja
      • router uniwersalny
  • Tematy poboczne
    • Izolowany CSS / spójny interfejs użytkownika / przewodniki po stylach i bibliotekach wzorców
    • Wydajność przy początkowym ładowaniu
    • Wydajność podczas korzystania z witryny
    • Ładowanie CSS’a
    • Ładowanie JS
    • Testy integracyjne

Contributors

Ta strona jest generowana przez Github Pages. Jego źródło można znaleźć pod adresem neuland/micro-frontends.