Co nowego w dyrektywie Angular NgOptimizedImage

Alex Castle
Alex Castle

Nieco ponad rok temu zespół Chrome Aurora wprowadził dyrektywę Angular NgOptimizedImage. Dyrektywa koncentruje się przede wszystkim na poprawie wydajności, co jest mierzone za pomocą podstawowych wskaźników internetowych. Łączy popularne optymalizacje obrazów i sprawdzone metody w interfejsie API przeznaczonym dla użytkowników, który nie jest znacznie bardziej skomplikowany niż standardowy element <img>.

W 2023 r. dodaliśmy do tej dyrektywy nowe funkcje. W tym poście omawiamy najważniejsze z tych nowych funkcji, wyjaśniając, dlaczego postanowiliśmy nadać każdej z nich priorytet oraz jak mogą one pomóc zwiększyć wydajność aplikacji Angular.

Nowe funkcje

Z czasem aplikacja NgOptimizedImage znacznie się udoskonaliła, w tym te nowe funkcje.

Tryb wypełniania

Dostosowywanie rozmiaru obrazów za pomocą atrybutów width i height to niezwykle ważna optymalizacja w celu ograniczenia przesunięcia układu, ponieważ przeglądarki muszą znać współczynnik proporcji obrazu, aby zaoszczędzić na nim miejsce. Jednak dobieranie rozmiaru obrazów wymaga od deweloperów aplikacji dodatkowej pracy i nie ma sensu w niektórych przypadkach użycia obrazów.

Ten problem to pierwsza duża funkcja dodana do podglądu komponentu graficznego po utworzeniu konta – tryb wypełnienia. W ten sposób deweloperzy mogą uwzględniać obrazy bez wyraźnego określenia ich rozmiaru i bez konieczności przesuwania układu.

W trybie wypełnienia wymóg określania rozmiaru obrazu jest wyłączony, a styl obrazu jest automatycznie dopasowywany tak, aby wypełnił element zawierający jego element. Dzięki temu współczynnik proporcji obrazu zostanie oddzielony od zajmowanego przez niego miejsca na stronie i zapewni większą kontrolę nad dopasowaniem obrazów do układu 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 zgodnie z powyższym przykładem kodu. Aby określić położenie obrazu w tle, użyj właściwości CSS object-fit i object-position tagu <div>.

// 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 zbioru Srcset

Jedna z najskuteczniejszych technik optymalizacji obrazów to zastosowanie atrybutu srcset, aby mieć pewność, że obrazy o prawidłowym rozmiarze będą pobierane z każdego urządzenia, na którym użytkownik korzysta z aplikacji. Korzystanie z usługi srcset w całej aplikacji pozwala zmniejszyć obciążenie sieci i znacznie poprawić podstawowy wskaźnik internetowy LCP.

Wadą atrybutu srcset jest to, że jego wdrożenie może być uciążliwe. Ręczne zapisywanie wartości srcset oznacza dodanie wielu wierszy znaczników do każdego elementu graficznego w aplikacji wraz z wieloma niestandardowymi adresami URL do każdego elementu srcset. Musisz też ustalić zestaw punktów przerwania, co jest skomplikowane, ponieważ mogą one odzwierciedlać gęstość ekranu i rozmiary widocznego obszaru na popularnych urządzeniach.

Dlatego dodanie automatycznego generowania zestawu srcset do dyrektywy NgOptimizedImage było ważnym kamieniem milowym po wprowadzeniu aplikacji na rynek. Dzięki temu każda aplikacja korzystająca z sieci CDN, która obsługuje zmienianie rozmiaru obrazów, będzie mogła otrzymywać pełne, dostosowywane zestawy srcset, automatycznie dodawane do każdego obrazu wygenerowanego za pomocą dyrektywy NgOptimizedImage.

Dołączyliśmy uproszczony interfejs API do konfigurowania właściwości sizes, który zapewnia, że każdy obraz otrzyma odpowiedni typ srcset. Jeśli nie podasz atrybutu sizes, wiemy, że obraz powinien mieć stały rozmiar i powinien otrzymać zależny od gęstości atrybut srcset, taki jak:

<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 sprawia, że obrazy są wyświetlane w rozmiarze uwzględniającym gęstość pikseli na ekranie urządzenia użytkownika.

Z drugiej strony, jeśli dodasz właściwość sizes, NgOptimizedImage wygeneruje elastyczny atrybut srcset zawierający punkty przerwania dla wielu typowych 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 wstępnego połączenia

Aby poprawić LCP, musisz skrócić czas spędzany przez użytkowników na pobieraniu obrazu LCP. W poprzedniej sekcji pokazaliśmy, jak srcset może pomóc w przesyłaniu mniejszych plików graficznych, ale równie ważnym elementem optymalizacji jest jak najszybsze rozpoczęcie przenoszenia. Możesz to zrobić na przykład za pomocą tagów link rel="preconnect", aby szybko rozpocząć połączenie z domeną obrazu.

Od początku usługa NgOptimizedImage ostrzega, jeśli nie uda Ci się wstępnie połączyć z domeną obrazu LCP, ale to nie jest idealne rozwiązanie – chcemy po prostu rozwiązać ten problem za Ciebie. Właśnie to robi NgOptimizedImage dzięki automatycznemu generowaniu wstępnego połączenia.

Aby umożliwić obsługę tej funkcji, używamy statycznej analizy kodu, aby wykryć domeny obrazów w modułach ładujących NgOptimizedImage i automatycznie wygenerować dla nich tagi linku typu preconnect. Nadal może być wymagane ręczne wstępne połączenie, ale w przypadku większości użytkowników takie automatyczne łączenie oznacza o 1 krok mniej potrzebny, aby uzyskać dobrą wydajność obrazu.

Ulepszona obsługa niestandardowych modułów ładujących

Kluczowym elementem interfejsu NgOptimizedImage jest architektura wczytywania, która umożliwia automatyczne generowanie adresów URL dopasowanych do sieci CDN aplikacji. Powszechnie używane sieci CDN zawierają zestaw wbudowanych modułów ładujących. Zapewniamy również możliwość korzystania z niestandardowych programów ładujących, które umożliwiają integrację NgOptimizedImage z niemal każdym rozwiązaniem do hostingu obrazów.

W momencie wprowadzenia na rynek 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 programu wczytującego. Dzięki rozszerzeniu niestandardowe moduły ładujące mogą być tak proste lub nawet tak złożone, jak wymaga tego infrastruktura obrazu aplikacji.

Ten przykład pokazuje, jak prosty niestandardowy program wczytujący może użyć interfejsu API loaderParams do wyboru między 2 alternatywnymi domenami 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 programu wczytującego można znaleźć w dokumentacji Angular.

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

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

W Angular 17 rozszerzamy zakres wskazówek dotyczących wydajności obrazów, tak aby objąć wszystkie aplikacje Angular. Jeśli teraz wykryjemy wzorce obrazów, które mogą pogarszać wydajność, takie jak leniwe ładowanie obrazu LCP lub pobranie pliku, którego rozmiar jest za duży dla danej strony, poinformujemy Cię o tym, nawet jeśli nie korzystasz z funkcji NgOptimizedImage.

Wydajność obrazu jest ważna w przypadku wszystkich aplikacji, dlatego nadal pracujemy nad dodatkowych zabezpieczeń, które pomogą zapobiegać typowym błędom w aplikacjach Angular.

Plany na przyszłość

Właśnie pracujemy nad kolejnym zestawem funkcji NgOptimizedImage. Choć wydajność obrazów pozostaje naszym głównym zagadnieniem, chcemy też dodać funkcje, które poprawią wrażenia programistów, aby mieć pewność, że NgOptimizedImage pozostanie atrakcyjną opcją umieszczania obrazów w aplikacjach Angular.

Jedną z funkcji, która jest dla nas priorytetowa, są obiekty zastępcze obrazów. Powszechnie używa się ich, aby poprawiać wygląd wczytywania obrazów w aplikacjach internetowych, ale ich nieprawidłowe wdrożenie może negatywnie wpłynąć na wydajność. Mamy nadzieję, że w NgOptimizedImage wbudowamy system zastępczy obrazów ukierunkowany na wydajność. Więcej informacji znajdziesz na naszym blogu.