[Uwaga] Ten artykuł został pierwotnie przygotowany w języku angielskim i został przetłumaczony na język polski.
Hydration (hydracja) to proces „aktywacji” strony renderowanej po stronie serwera na kliencie poprzez dodanie interaktywności. Gdy aplikacja jest renderowana po stronie serwera (SSR), serwer generuje dokument HTML i wysyła go do klienta. Po stronie klienta Angular musi przejąć kontrolę i dodać interaktywność do statycznego kodu HTML – proces ten nazywamy właśnie „hydracją”.
W tradycyjnym Angular SSR (przeczytaj więcej o implementacji Angular SSR w artykule mojego kolegi – Pawła Żurawskiego), cała aplikacja podlega procesowi hydracji za jednym razem, gdy tylko klient otrzyma HTML. Może to być nieefektywne, zwłaszcza jeśli aplikacja jest duża lub złożona, ponieważ cała strona musi zostać poddana procesowi bootstrapu jednocześnie, co może prowadzić do opóźnień w uzyskaniu interaktywności strony.
Incremental hydration to przełomowa funkcja mająca na celu optymalizację wydajności aplikacji renderowanych po stronie serwera poprzez usprawnienie ładowania i wykonywania kodu JavaScript po stronie klienta. Funkcja ta pomaga skrócić czas potrzebny na uzyskanie interaktywności strony poprzez stopniowy bootstrapping części aplikacji, zamiast robienia tego wszystkiego naraz. Angular inkrementalnie hydruje mniejsze części aplikacji w miarę potrzeb. Dzięki hydracji tylko niezbędnych fragmentów, incremental hydration może również pomóc zminimalizować wpływ nieużywanego JavaScriptu, co dodatkowo poprawia wydajność.
Dzięki incremental hydration Angular dzieli aplikację na mniejsze „strefy hydracji” (hydration zones) lub „chunki hydracji” (hydration chunks). Gdy klient otrzyma wyrenderowany na serwerze HTML, Angular najpierw rozpocznie hydrację istotnych lub widocznych części strony. Gdy staną się one interaktywne, Angular będzie kontynuował hydrację pozostałych obszarów strony w tle.
Incremental hydration pozwala oznaczać sekcje szablonu za pomocą znanej składni @defer (wprowadzonej w Angularze 17), instruując Angulara, aby ładował je leniwie (lazy load) i hydrował tylko wtedy, gdy wystąpią określone triggery.
Przykład:
@defer (hydrate on viewport) {
<your-component />
}
Więcej o incremental hydration możesz przeczytać w dokumentacji.
Event replay to funkcja w Angularze, która zapewnia płynne wykonywanie interakcji użytkownika w aplikacjach renderowanych po stronie serwera (SSR) lub częściowo hydrowanych.
Mechanizm ten przechwytuje i kolejkuję interakcje użytkownika (np. kliknięcia, wysłania formularzy, przewijanie), które wystąpią, zanim aplikacja zostanie w pełni hydrowana. Gdy proces hydracji zostanie zakończony, a JavaScript po stronie klienta przejmie kontrolę, te zakolejkowane zdarzenia są odtwarzane (replayed) i obsługiwane tak, jakby wystąpiły już po hydracji.
Począwszy od wersji Angular 19, event replay jest stabilny i domyślnie włączony dla wszystkich nowych aplikacji korzystających z server-side renderingu, co czyni je bardziej solidnymi i interaktywnymi bez konieczności dodatkowej konfiguracji.
Angular CLI będzie teraz domyślnie generować taką konfigurację:
bootstrapApplication(App, {
providers: [
provideClientHydration(withEventReplay())
]
});
Komponenty standalone zostały wprowadzone w v14, a ponad 90% programistów w ostatniej ankiecie zadeklarowało, że korzysta z tej funkcji. W Angularze 19 komponenty standalone są teraz domyślnym sposobem definiowania i budowania komponentów. Zmiana ta upraszcza metadane wszystkich komponentów standalone, dyrektyw i pipe’ów.
Podczas aktualizacji do v19, CLI automatycznie usunie właściwość metadanych standalone dla wszystkich abstrakcji typu standalone, a dla tych, które nie są standalone, ustawi ją na false.
Aby wymusić stosowanie nowoczesnych API w projekcie, wprowadzono nową flagę kompilatora. Wygeneruje ona błąd, jeśli wykryje komponent, dyrektywę lub pipe, który nie jest typu standalone. Aby włączyć tę funkcję, skonfiguruj plik tsconfig.json w następujący sposób:
{
"angularCompilerOptions": {
"strictStandalone": true
}
}
[..]
[ERROR] TS-992023: Only standalone components/directives are allowed when 'strictStandalone' is enabled. [plugin angular-compiler]
Funkcja linkedSignal w Angularze to eksperymentalne API, które wprowadza nowy sposób zarządzania stanem ściśle powiązanym z innymi stanami reaktywnymi. Funkcja ta jest szczególnie przydatna w scenariuszach, w których dany fragment stanu zależy od innego i powinien być odpowiednio aktualizowany, gdy stan źródłowy ulegnie zmianie.
linkedSignal tworzy writable signal (sygnał z możliwością zapisu), który automatycznie aktualizuje swoją wartość na podstawie funkcji obliczeniowej (computation function) za każdym razem, gdy jego sygnał źródłowy ulegnie zmianie. Zapewnia to spójność stanu zależnego z jego źródłem.
W przeciwieństwie do sygnałów typu computed, które są tylko do odczytu, linkedSignal pozwala na ręczne aktualizacje. Oznacza to, że można ustawić jego wartość bezpośrednio, co zapewnia elastyczność w zarządzaniu stanami, które mogą wymagać zarówno automatycznych, jak i ręcznych korekt.
W prostszych scenariuszach można użyć skróconej składni:
animals = signal(['guinea pig', 'cat', 'dog']); selectedAnimal = linkedSignal(() => animals()[0]); console.log(selectedAnimal()); // 'guinea pig' animals.set(['elephant','rabbit']); console.log(selectedAnimal()); // 'elephant'
Za każdym razem, gdy tablica animals się zmienia, selectedAnimal zmieni się na pierwszy element z nowej listy.
W niektórych przypadkach nowa wartość musi zostać obliczona na podstawie poprzedniej wartości. Wówczas warto rozważyć bardziej zaawansowaną składnię z definicją źródła (source) i obliczeń (computation):
animals = signal<string[]>(['guinea pig', 'cat', 'dog']);
selectedAnimal = linkedSignal({
source: animals,
computation: (newAnimals: string[], previous?: { value: string }) => {
// Jeśli poprzedni wybór istnieje na nowej liście, zachowaj go. W przeciwnym razie wybierz pierwsze zwierzę.
return previous && newAnimals.includes(previous.value)
? previous.value
: newAnimals[0];
},
});
// Zachowaj obecny wybór podczas resetowania listy zwierząt (np. po ponownym pobraniu z API)
console.log(this.selectedAnimal()); // 'guinea pig'
this.animals.set(['horse', 'guinea pig']);
console.log(this.selectedAnimal()); // 'guinea pig'
this.animals.set(['horse', 'fish']);
console.log(this.selectedAnimal()); // 'horse'
// Ponieważ linkedSignal jest zapisywalny, zwierzę może zostać wybrane również ręcznie (np. po kliknięciu w UI)
this.selectedAnimal.set('dog');
console.log(this.selectedAnimal()); // 'dog'
Więcej o linkedSignals przeczytasz w dokumentacji.
Angular 19 wprowadza eksperymentalne API resource oraz rxResource, aby usprawnić asynchroniczne pobieranie i zarządzanie danymi poprzez wykorzystanie sygnałów oraz obserwowalnych (observables). Warto zaznaczyć, że oba te interfejsy mogą jeszcze ulec zmianom, zanim staną się stabilne w przyszłych wydaniach.
Funkcja resource tworzy reaktywne źródło danych, które pobiera asynchroniczne dane i dostarcza sygnały do monitorowania ich stanu.
Główne cechy:
Przykład użycia:
const RESOURCE_URL = 'https://lorem.ipsum';
const id = signal(1);
const myResource = resource({
request: () => ({ id: id() }),
loader: ({ request, abortSignal }) =>
fetch(${RESOURCE_URL}${request.id}, { signal: abortSignal }).then(response => response.json()),
});
W tym przykładzie myResource pobiera dane na podstawie id signal. Zmiana id powoduje nowe pobranie, przy czym poprzednie żądanie jest przerywane, jeśli wciąż było w toku.
Funkcja rxResource oferuje podobną funkcjonalność, jednak podczas gdy resource() korzysta z loadera opartego na promise, rxResource() integruje się z RxJS observables. Jest to rozwiązanie dedykowane programistom preferującym strumienie do operacji asynchronicznych. Nadaje się do bardziej złożonych scenariuszy i wykorzystuje pełną moc RxJS do obsługi ponowień (retries), anulowań, łączenia strumieni i innych. Obecnie rxResource bierze pod uwagę tylko pierwszą wyemitowaną wartość z observable; kolejne emisje są ignorowane.
Przykład użycia:
const RESOURCE_URL = 'https://lorem.ipsum';
const id = signal(1);
const myRxResource = rxResource({
request: () => ({ id: id() }),
loader: ({ request }) =>
fromFetch(${RESOURCE_URL}${request.id}).pipe(
switchMap(response => response.json())
),
});
Tutaj myRxResource pobiera dane jako strumień observable, reagując na zmiany w sygnale id.
W Angularze 19 wprowadzono konfigurację tras serwera (server route configuration), aby zapewnić programistom precyzyjną kontrolę nad sposobem renderowania każdej ścieżki w aplikacji. Funkcja ta pozwala określić tryb renderowania dla poszczególnych route’ów, dając wybór między Server-Side Rendering (SSR), Static Site Generation (SSG), a Client-Side Rendering (CSR).
Aby skonfigurować trasy serwera, definiujesz tablicę obiektów ServerRoute, zazwyczaj w pliku o nazwie app.routes.server.ts. Każdy ServerRoute określa ścieżkę oraz odpowiadający jej tryb renderowania przy użyciu enuma RenderMode.
Przykład użycia:
import { RenderMode, ServerRoute } from '@angular/ssr';
export const serverRoutes: ServerRoute[] = [
{
path: '', // Ścieżka główna
renderMode: RenderMode.Client, // Renderowane po stronie klienta (CSR)
},
{
path: 'about',
renderMode: RenderMode.Prerender, // Prerenderowane w czasie budowania (SSG)
},
{
path: 'profile',
renderMode: RenderMode.Server, // Renderowane na serwerze przy każdym żądaniu (SSR)
},
{
path: '**', // Ścieżka typu wildcard dla pozostałych tras
renderMode: RenderMode.Server, // Domyślnie SSR
},
];
Angular 19 wprowadza trzy tryby renderowania, które można przypisać do tras:
Począwszy od Angulara 19, Angular CLI zawiera funkcję zgłaszania ostrzeżeń dotyczących nieużywanych importów w aplikacji. To ulepszenie ma na celu poprawę czystości kodu i produktywności programistów poprzez pomoc w identyfikacji niepotrzebnych lub przestarzałych importów w plikach projektu.
Przykład:
@Component({
selector: 'test-component',
imports: [IconComponent],
templateUrl: './test-component.component.html',
})
[...]
[WARNING] TS-998113: All imports are unused [plugin angular-compiler]
imports: [IconComponent]
Angular ewoluuje dynamicznie – 19. wersja przynosi mnóstwo ulepszeń, które podnoszą komfort pracy dewelopera (developer experience) oraz ogólną wydajność aplikacji. Przeanalizuj te funkcjonalności i zacznij wdrażać je we własnych projektach Angularowych – z pewnością ułatwią Ci one życie w wielu sytuacjach.
Jeśli interesuje Cię więcej treści o Angularze, sprawdź inne publikacje na naszym blogu:
Oto odpowiedzi na kilka powszechnych pytań dotyczących aplikacji Angular, jego funkcji oraz rozwoju.
Aktualna wersja to Angular 19.
Wśród najważniejszych funkcji znajdują się: incremental hydration, stabilny event replay, zmiany w komponentach standalone, nowy eksperymentalny prymityw linked signal, eksperymentalne API do strumieniowego pobierania danych, hybrydowe renderowanie oraz ostrzeżenia o nieużywanych importach standalone.
Angular 19 został wydany 19 listopada 2024 roku.
To kompleksowa biblioteka komponentów zgodna z Material Design, przeznaczona dla Angulara.
Angular Language Service to usługa wspomagająca edytory kodu w obsłudze błędów, ich identyfikacji, podpowiadaniu składni (completions), wyświetlaniu wskazówek oraz nawigacji wewnątrz szablonów Angulara.
Hot module replacement (HMR) pozwala deweloperom na wymianę komponentów i modułów aplikacji w czasie rzeczywistym (w trakcie działania programu) bez utraty stanu aplikacji.