# Angular @defer w 2026: deklaratywny lazy loading dla szybszych aplikacji > Opanuj bloki @defer w Angularze do deklaratywnego lazy loadingu. Dogłębne omówienie wyzwalaczy, prefetchingu, hydratacji przyrostowej, zachowania w SSR i praktycznych wzorców wydajności. - Published: 2026-06-14 - Updated: 2026-06-17 - Author: Anthony Fillion-Maillet - Tags: angular, angular-defer, lazy-loading, performance, ssr, signals, deep-dive - Reading time: 9 min --- Bloki `@defer` w Angularze rozwiązują problem, którego lazy loading oparty na routerze nigdy nie potrafił rozwiązać: ładowanie pojedynczych komponentów, dyrektyw i pipe'ów na żądanie bez przebudowywania aplikacji na osobne trasy. Wprowadzony w Angularze 17 i ustabilizowany do wersji 22, `@defer` zamienia to, co wcześniej wymagało dynamicznych importów, flag `*ngIf` i konfiguracji webpacka, w jeden deklaratywny blok szablonu. > **Co robi @defer** > > `@defer` instruuje kompilator Angulara, aby podzielił opakowane komponenty na osobne fragmenty JavaScript (chunki), ładowane dopiero po spełnieniu warunku wyzwalacza. Przeglądarka pobiera mniej JavaScriptu na starcie, co poprawia Largest Contentful Paint (LCP) i Time to First Byte (TTFB) bez ręcznej konfiguracji code-splittingu. ## Jak @defer działa pod maską Gdy kompilator Angulara napotyka blok `@defer`, wyodrębnia każdy samodzielny (standalone) komponent, dyrektywę i pipe znajdujące się wewnątrz niego do osobnego fragmentu. Główny pakiet jest dostarczany bez tych zależności. W czasie wykonania Angular ocenia warunek wyzwalacza i pobiera fragment za pomocą dynamicznego wywołania `import()`. Blok obsługuje cztery podbloki, które kontrolują to, co widzi użytkownik podczas cyklu ładowania: ```typescript // app.component.html @defer (on viewport) { } @placeholder {
} @loading (minimum 200ms) { } @error {

Failed to load the dashboard. Please refresh.

} ``` `@placeholder` renderuje się przed uruchomieniem wyzwalacza. `@loading` pojawia się podczas pobierania fragmentu, z opcjonalnym czasem `minimum`, który zapobiega migotaniu (flicker). `@error` przechwytuje błędy sieci lub fragmentu. Parametr `minimum` w `@loading` zapobiega błyśnięciu spinnera, gdy fragment ładuje się szybko z pamięci podręcznej. Jedno ograniczenie: każda zależność wewnątrz `@defer` musi być standalone. Komponenty niebędące standalone, zadeklarowane w `NgModule`, nie mogą być odroczone i zostaną załadowane zachłannie (eagerly) niezależnie od opakowania `@defer`. ## Typy wyzwalaczy: kontrola momentu ładowania komponentów Angular udostępnia siedem wbudowanych wyzwalaczy, z których każdy odpowiada innej strategii ładowania. Wiele wyzwalaczy można łączyć średnikami i są one oceniane jako warunki OR. ```typescript // product-page.component.html // Loads when the browser goes idle (default) @defer { } // Loads when the element enters the viewport @defer (on viewport) { } // Loads on click or keydown @defer (on interaction) { } @placeholder { } // Loads on mouseenter or focusin @defer (on hover) { } // Loads after 3 seconds @defer (on timer(3s)) { } // Loads immediately after initial render @defer (on immediate) { } ``` Wyzwalacz `on viewport` wewnętrznie korzysta z [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). Wyzwalacz `on idle` deleguje do `requestIdleCallback`, co czyni go najbezpieczniejszym domyślnym wyborem dla treści poniżej linii zgięcia (below-the-fold). Wyzwalacz `on timer` przyjmuje czasy w milisekundach (`500ms`) lub sekundach (`3s`). ### Wyzwalacz `when` dla warunków reaktywnych Poza wyzwalaczami opartymi na zdarzeniach, `when` przyjmuje dowolne wyrażenie logiczne, w tym odczyty sygnałów: ```typescript // dashboard.component.ts export class DashboardComponent { showAdvanced = signal(false); } // dashboard.component.html @defer (when showAdvanced()) { } @placeholder { } ``` Łączenie `on` i `when` jest dozwolone. Angular traktuje je jako OR: blok ładuje się, gdy spełniony jest którykolwiek z warunków. ## Prefetching: oddzielenie pobierania od wyświetlania Prefetching oddziela moment pobierania fragmentu od momentu renderowania komponentu. Eliminuje to odczuwane opóźnienie, pobierając JavaScript zanim użytkownik go wyzwoli. ```typescript // settings.component.html @defer (on interaction; prefetch on idle) { } @placeholder { } ``` W tym wzorcu przeglądarka pobiera fragment `account-settings` w czasie bezczynności. Gdy użytkownik kliknie, komponent renderuje się natychmiast, ponieważ kod jest już dostępny. Prefetching przyjmuje te same typy wyzwalaczy co główna klauzula `on`. Częsty wzorzec dla dashboardów: prefetch ciężkich komponentów w czasie bezczynności, przy jednoczesnym odroczeniu renderowania do momentu wejścia w viewport. ```typescript // analytics.component.html @defer (on viewport; prefetch on idle) { } @placeholder (minimum 100ms) {
} ``` `minimum` w `@placeholder` zapobiega przeskokowi układu (layout flash), gdy użytkownik szybko przewija, a odroczony komponent ładuje się niemal natychmiast. ## @defer a renderowanie po stronie serwera (SSR) Na serwerze bloki `@defer` domyślnie renderują zawartość `@placeholder`. Odroczony komponent nigdy nie jest renderowany po stronie serwera. To zachowanie jest celowe: pobieranie fragmentu ma sens wyłącznie w kontekście przeglądarki. Dla treści krytycznej dla SEO oznacza to, że `@placeholder` musi zawierać sensowny HTML, a nie tylko spinner: ```typescript // blog-post.component.html @defer (on viewport) { } @placeholder {

Comments

Loading comments...

} ``` Wyszukiwarki indeksują zawartość placeholdera podczas SSR. Opisowy placeholder zapewnia, że strona pozostaje kompletna semantycznie. ## Hydratacja przyrostowa z @defer Angular 19 wprowadził [hydratację przyrostową](https://angular.dev/guide/incremental-hydration) w wersji developer preview, a Angular 22 stabilizuje ją jako funkcję gotową do produkcji. Hydratacja przyrostowa rozszerza `@defer` o wyzwalacz `hydrate`, który kontroluje, kiedy komponent renderowany na serwerze staje się interaktywny po stronie klienta. ```typescript // product-page.component.html @defer (hydrate on viewport) { } @defer (hydrate on interaction) { } ``` W przeciwieństwie do standardowego `@defer`, hydratacja przyrostowa renderuje pełny HTML komponentu na serwerze. Klient otrzymuje kompletny markup, ale pomija hydratację komponentu aż do uruchomienia wyzwalacza. Efekt: przeglądarka natychmiast maluje pełną stronę, ale wykonanie JavaScriptu jest odroczone. Zespół Angulara raportuje stałe poprawy wyników LCP rzędu 40-50% przy stosowaniu hydratacji przyrostowej na stronach o dużej ilości treści. Angular DevTools w wersji 22 wizualizuje stany hydratacji (oczekujący, zhydratowany, błąd) bezpośrednio w inspektorze komponentów. ## Wzorce z praktyki i strategia wydajności ### Wzorzec 1: Ciężki dashboard z wieloma odroczonymi panelami ```typescript // dashboard.component.html
@defer (on viewport; prefetch on idle) { } @placeholder { } @defer (on viewport; prefetch on idle) { } @placeholder { } @defer (on interaction) { } @placeholder { }
``` Każdy panel ładuje się niezależnie. Panel eksportu pozostaje niezaładowany, dopóki użytkownik wyraźnie go nie zażąda, co oszczędza pełne pobranie fragmentu dla użytkowników, którzy nigdy nie eksportują danych. ### Wzorzec 2: Warunkowe ładowanie funkcji z sygnałami ```typescript // editor.component.ts export class EditorComponent { user = inject(UserService).currentUser; isPremium = computed(() => this.user()?.plan === 'premium'); } // editor.component.html @defer (when isPremium()) { } @placeholder { } ``` Użytkownicy z darmowym planem nigdy nie pobierają fragmentu asystenta AI. Baner z propozycją upgrade'u pełni rolę zarówno placeholdera, jak i zachęty do konwersji. ### Unikanie typowych pułapek Zagnieżdżanie bloków `@defer` z tym samym wyzwalaczem powoduje równoczesne pobieranie fragmentów. Rozłóż wyzwalacze pomiędzy zagnieżdżone bloki: ```typescript // Avoid: both fire on idle simultaneously @defer { @defer { } } // Better: outer on idle, inner on viewport @defer (on idle) { } // Inside wrapper-component template: @defer (on viewport) { } ``` Kolejna pułapka: używanie `@defer` dla komponentów znajdujących się już na krytycznej ścieżce renderowania. Odraczanie treści powyżej linii zgięcia (above-the-fold) zwiększa LCP, ponieważ przeglądarka musi pobrać i wykonać fragment przed namalowaniem. Zarezerwuj `@defer` dla treści poniżej linii zgięcia lub wyzwalanej przez użytkownika. ## @defer kontra lazy loading oparty na routerze Lazy loading oparty na routerze i `@defer` uzupełniają się nawzajem. Lazy loading routera dzieli na poziomie trasy, odraczając całe moduły funkcjonalne. `@defer` dzieli wewnątrz szablonu, odraczając pojedyncze komponenty. | Aspekt | Lazy loading routera | @defer | |--------|-------------------|--------| | Granularność | Poziom trasy | Poziom komponentu | | Wyzwalacz | Zdarzenie nawigacji | viewport, idle, interaction, hover, timer, warunek | | Zachowanie w SSR | Pełny render na serwerze | Placeholder na serwerze | | Wymaga standalone | Nie (działa z NgModules) | Tak (tylko standalone) | | Prefetching | `preloadingStrategy` | klauzula `prefetch on` | | Zastosowanie | Moduły funkcjonalne, strony | Widżety, panele, warunkowy UI | Typowa aplikacja używa obu: lazy loadingu routera dla obszarów funkcjonalnych najwyższego poziomu oraz `@defer` dla ciężkich komponentów w obrębie tych obszarów. ## Pytania rekrutacyjne dotyczące Angular @defer Rozmowy techniczne coraz częściej obejmują `@defer`, w miarę jak staje się on centralnym elementem strategii wydajności Angulara. Oto wzorce, które często pojawiają się w [pytaniach rekrutacyjnych z Angulara](/technologies/angular/interview-questions/standalone-components). **P: Co się stanie, jeśli komponent niebędący standalone zostanie umieszczony wewnątrz @defer?** Komponent ładuje się zachłannie, niezależnie od bloku `@defer`. Kompilator Angulara nie może wyodrębnić komponentów zadeklarowanych w NgModule do osobnych fragmentów. Nie jest zgłaszany żaden błąd, ale optymalizacja po cichu zawodzi. **P: Jak @defer zachowuje się podczas SSR?** Serwer renderuje zawartość `@placeholder`. Odroczony komponent nigdy nie jest renderowany po stronie serwera. Hydratacja następuje po stronie klienta po uruchomieniu wyzwalacza (lub przez `hydrate on` w przypadku hydratacji przyrostowej). **P: Czy @defer można używać z OnPush change detection?** Tak. `@defer` jest funkcją na poziomie szablonu i działa z dowolną strategią wykrywania zmian. Odroczony komponent po załadowaniu stosuje własną konfigurację wykrywania zmian. **P: Jaka jest różnica między `on idle` a `on immediate`?** `on idle` czeka, aż przeglądarka zakończy wszystkie oczekujące zadania poprzez `requestIdleCallback`. `on immediate` uruchamia się tuż po zakończeniu przez Angular pierwszego przebiegu renderowania, bez czekania na stan bezczynności. `on immediate` jest przydatny dla komponentów, które powinny załadować się szybko, ale nie blokować pierwszego malowania. Aby uzyskać szerszy zestaw materiałów do przygotowania na rozmowę z Angulara, zobacz [moduł change detection w Angularze](/technologies/angular/interview-questions/change-detection) oraz [moduł sygnałów Angulara](/technologies/angular/interview-questions/angular-signals). ## Podsumowanie - `@defer` dzieli komponenty standalone na osobne fragmenty ładowane na żądanie, redukując początkowy rozmiar pakietu bez przebudowy tras - Siedem typów wyzwalaczy (`idle`, `viewport`, `interaction`, `hover`, `timer`, `immediate`, `when`) pokrywa każdą strategię ładowania, od pasywnej po sterowaną przez użytkownika - `prefetch on` oddziela pobieranie fragmentu od renderowania komponentu, eliminując odczuwane opóźnienie w komponentach wyzwalanych przez użytkownika - Hydratacja przyrostowa (`hydrate on`) renderuje pełny HTML na serwerze, odraczając wykonanie JavaScriptu do klienta, co daje 40-50% poprawy LCP na stronach o dużej ilości treści - Zawartość `@placeholder` renderuje się podczas SSR i musi być sensowna semantycznie ze względu na SEO - `@defer` uzupełnia lazy loading oparty na routerze: trasy dla podziału na poziomie funkcji, `@defer` dla podziału na poziomie komponentów w szablonach - Komponenty niebędące standalone nie mogą być odroczone i po cichu ładują się zachłannie --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/pl/blog/angular/angular-defer-loading-declarative-lazy-loading-guide