Co nowego w dyrektywie Angular NgOptimizedImage

Zamek Alex
Zamek Alex

Nieco ponad rok temu zespół Chrome Aurora wprowadził dyrektywę Angular NgOptimizedImage. Dyrektywa koncentruje się głównie na poprawie wydajności mierzonej przy użyciu podstawowych wskaźników internetowych. Łączy typowe optymalizacje obrazów i sprawdzone metody w przeznaczony dla użytkownika interfejs API, który nie jest znacznie bardziej skomplikowany niż standardowy element <img>.

W 2023 r. rozszerzyliśmy tę dyrektywę o nowe funkcje. W tym poście opisujemy najważniejsze z nich, podkreślając znaczenie każdej z nich i wyjaśniając, jak mogą one pomóc zwiększyć wydajność aplikacji Angular.

Nowe funkcje

Na przestrzeni czasu technologia NgOptimizedImage znacznie się poprawiła, m.in. pojawiły się nowe funkcje.

Tryb wypełniania

Określanie rozmiaru obrazów za pomocą atrybutów width i height jest niezwykle ważne w celu ograniczenia przesunięcia układu, ponieważ przeglądarki muszą znać współczynnik proporcji obrazu, aby zaoszczędzić na nim miejsce. Jednak określanie rozmiaru obrazów to dodatkowe zadanie dla programistów aplikacji i nie ma sensu w niektórych przypadkach użycia obrazów.

Aby rozwiązać ten problem, jest to pierwsza duża funkcja dodana do komponentu graficznego po wersji przedpremierowej dla programistów: tryb wypełnienia. Dzięki temu deweloperzy mogą dodawać obrazy bez wyraźnego określenia ich rozmiaru i bez przesunięcia układu.

W trybie wypełniania wymagania dotyczące rozmiaru obrazu są wyłączone, a styl obrazu jest automatycznie dostosowywany do wypełnienia jego elementu. Pozwala to odseparować format obrazu od przestrzeni, jaką zajmuje on na stronie, i daje większą kontrolę nad tym, jak obrazy wpasowują się w układ strony.

Tryb wypełnienia wykorzystuje NgOptimizedImage jako skuteczniejszą alternatywę dla właściwości CSS background-image. Umieść obraz w elemencie <div> lub innym elemencie, który miałby styl background-image, a następnie włącz tryb wypełnienia, jak pokazano w poprzednim przykładzie kodu. Użyj właściwości CSS object-fit i object-position w interfejsie <div>, aby określić położenie obrazu w tle.

// Height and width are required
<img ngSrc="example.com" height="300" width="400">

// Unless you use fill mode!
<div style="width: 100vw; height: 50em; position: relative">
  <img ngSrc="example.com" fill>
</div>

Generowanie Srcset

Jedną z najskuteczniejszych technik optymalizacji obrazów jest użycie atrybutu srcset, aby zapewnić pobieranie obrazów o prawidłowym rozmiarze dla każdego urządzenia, na którym korzystasz z aplikacji. Używanie srcset w aplikacji może zapobiec marnowaniu przepustowości i znacznie poprawić podstawowy wskaźnik internetowy LCP.

Wadą atrybutu srcset jest to, że jego wdrożenie może być kłopotliwe. Ręczne zapisywanie wartości srcset oznacza dodanie wielu wierszy znaczników do każdego elementu obrazu w aplikacji wraz z kilkoma niestandardowymi adresami URL dla każdego atrybutu srcset. Trzeba też ustalić zestaw punktów przerwania. Jest to skomplikowane, ponieważ mogą one reprezentować zarówno gęstość ekranu, jak i rozmiar widocznego obszaru w przypadku typowych urządzeń.

Właśnie dlatego dodanie automatycznego generowania zbioru zasobów srcset do dyrektywy NgOptimizedImage było ważnym krokiem po premierze. Dzięki temu każda aplikacja korzystająca z sieci CDN, która obsługuje zmianę rozmiaru obrazu, może automatycznie dodawać pełny i konfigurowalny element srcset do każdego obrazu wygenerowanego za pomocą dyrektywy NgOptimizedImage.

Dodaliśmy uproszczony interfejs API do ustawiania właściwości sizes, który służy do sprawdzania, czy każde zdjęcie otrzymuje prawidłowy typ srcset. Jeśli nie podasz atrybutu sizes, wiemy, że obraz ma mieć stały rozmiar i powinien otrzymać zależny od gęstości atrybut srcset, taki jak poniżej:

<img src="www.example.com/image.png" srcset="www.example.com/image.png?w=400 1x, www.example.com/image.png?w=800 2x" >

Ten rodzaj atrybutu srcset zapewnia, że obrazy są wyświetlane w rozmiarze uwzględniającym gęstość pikseli na urządzeniu użytkownika.

Z drugiej strony, jeśli dodasz właściwość sizes, NgOptimizedImage wygeneruje elastyczny zasób srcset, który zawiera punkty przerwania dla wielu popularnych rozmiarów urządzeń i obrazów, korzystając z tej domyślnej listy punktów przerwania:

[16, 32, 48, 64, 96, 128, 256, 384, 640, 750, 828, 1080, 1200, 1920, 2048, 3840]

Generowanie połączenia przed połączeniem

Aby poprawić wartość LCP, należy skrócić czas poświęcany przez użytkowników na pobieranie obrazu LCP. W poprzedniej sekcji omówiliśmy, jak srcset może pomóc w przenoszeniu mniejszych plików graficznych, ale równie ważna optymalizacja jest jak najszybsze rozpoczęcie przenoszenia. Możesz to zrobić na przykład za pomocą tagów link rel="preconnect", aby przyspieszyć połączenie z domeną obrazu.

Od początku usługa NgOptimizedImage ostrzegała, jeśli nie uda Ci się wstępnie połączyć z domeną obrazu LCP, ale ostrzeżenie nie jest idealnym rozwiązaniem. Rozwiążemy ten problem za Ciebie. Właśnie to robi teraz NgOptimizedImage dzięki automatycznemu generowaniu połączeń z wyprzedzeniem.

Do obsługi tej funkcji używamy analizy kodu statycznego, aby wykrywać domeny obrazów w modułach ładowania NgOptimizedImage i automatycznie generować dla nich tagi linków umożliwiające połączenie z siecią. W niektórych przypadkach wymagane jest ręczne połączenie z internetem, ale w przypadku większości użytkowników automatyczne wstępne połączenie oznacza o jeden krok mniej potrzebny do uzyskania dobrej jakości obrazu.

Rozszerzona obsługa niestandardowych modułów ładowania

Kluczowym elementem NgOptimizedImage jest architektura wczytywania, która umożliwia dyrektywie automatyczne generowanie adresów URL dopasowanych do sieci CDN obrazu aplikacji. W przypadku popularnych sieci CDN dostępny jest zestaw wbudowanych modułów ładowania. Zapewniamy również możliwość korzystania z niestandardowych modułów wczytywania, które umożliwiają integrację NgOptimizedImage z prawie każdym rozwiązaniem do hostingu obrazów.

W momencie wprowadzenia te niestandardowe moduły ładowania miały ograniczony zakres i mogły odczytywać tylko atrybut width z elementu graficznego. W odpowiedzi na opinie użytkowników dodaliśmy obsługę dostosowywanej struktury danych loaderParams, która umożliwia przekazywanie dowolnych danych z elementu graficznego do niestandardowego modułu wczytywania. Dzięki rozszerzaniu niestandardowe moduły ładowania mogą być tak proste lub tak złożone, jak wymagają tego infrastruktura obrazów aplikacji.

Ten przykład pokazuje, jak prosty niestandardowy program ładujący może użyć interfejsu API loaderParams do wyboru 2 alternatywnych domen obrazów:

const myCustomLoader = (config: ImageLoaderConfig) => {
  if (config.loaderParams?.alternateDomain) {
    return `https://alternate.domain.com/images/${config.src}`
  }
  return `https://primary.domain.com/images/${config.src}`;
};

Przykład bardziej złożonego niestandardowego modułu ładowania jest dostępny w dokumentacji Angular.

Rozszerzone wskazówki dotyczące skuteczności obrazów

Do tej pory każdy alert dotyczący wydajności obrazu, który dodaliśmy do Angular, był częścią dyrektywy NgOptimizedImage. Jeśli nie zastosujesz danej dyrektywy w aplikacji, nie zobaczysz żadnych wskazówek dotyczących problemów z wydajnością obrazów.

W Angular 17 rozszerzymy zakres wskazówek dotyczących wydajności obrazów, aby objąć wszystkie aplikacje Angular. Teraz, gdy wykryjemy wzorce obrazów, o których wiemy, że są błędy powodujące spadek wydajności, takie jak leniwe ładowanie obrazu LCP lub pobieranie pliku zbyt dużego na stronę, powiadomimy Cię o tym, nawet jeśli nie korzystasz z NgOptimizedImage.

Wydajność obrazów jest ważna w przypadku wszystkich aplikacji, dlatego będziemy nadal budować bariery, aby zapobiegać typowym błądom w aplikacjach Angular.

Plany na przyszłość

Pracujemy już nad kolejnym zestawem funkcji dla NgOptimizedImage. Wydajność obrazów nadal jest naszym głównym problemem, ale chcemy też dodać funkcje, które poprawią wrażenia programistów, dzięki czemu NgOptimizedImage pozostanie atrakcyjną opcją do umieszczania obrazów w aplikacjach Angular.

Funkcją, która ma dla nas priorytet, są obiekty zastępcze obrazów. Są one często stosowane, aby poprawić jakość wczytywania obrazów w aplikacjach internetowych, ale jeśli zostaną nieprawidłowo zaimplementowane, mogą mieć negatywny wpływ na wydajność. Mamy nadzieję, że uda nam się umieścić w NgOptimizedImage system obiektów zastępczych obrazów skoncentrowany na wydajności. Więcej informacji znajdziesz na naszym blogu.