В мае 2022 года команды Aurora и Angular объявили, что будут совместно работать над директивой по изображениям для Angular. Директива была недавно выпущена для предварительной версии для разработчиков как часть Angular v14.2. В этом посте рассказывается о том, как новая директива изображения NgOptimizedImage
поддерживает оптимизацию изображений в Angular.
Фон
Изображения являются распространенным и важным компонентом взаимодействия с пользователем в Интернете: 99,9% веб-страниц генерируют запросы на одно или несколько изображений. Изображения также вносят наибольший вклад в вес страницы, составляя в среднем 982 килобайта на страницу.
Из-за растущего количества и размера изображения могут снижать производительность веб-страниц и влиять на показатели Core Web Vitals . Для 79,4% страниц рабочего стола изображение было самым большим элементом Contentful Paint ( LCP ) в 2021 году. Таким образом, стремление к оптимизированным изображениям стало постоянным стремлением для многих из нас.
Команда Aurora верит в возможность использования возможностей платформ для предоставления встроенных решений распространенных проблем разработчиков. Их первым шагом в области оптимизации изображений стал компонент изображений Next.js. Они считали этот компонент испытательным полигоном для проверки того, может ли улучшение опыта разработчиков (DX) при оптимизации изображений привести к повышению производительности большего количества приложений, использующих фреймворки.
Первый набор результатов от пользователя Next.js Leboncoin был обнадеживающим. Leboncoin продемонстрировал значительное улучшение LCP (с 2,4 до 1,7 с) после того, как они начали использовать next/image
. Последующее принятие next/image
в сообществе сыграло роль в увеличении количества источников Next.js, соответствующих пороговым значениям LCP. Вскоре появились запросы на аналогичные функции в других фреймворках, одним из которых является Angular .
В результате Aurora проконсультировалась с Angular и Nuxt для создания прототипов компонентов изображений для этих фреймворков. Компонент изображения Nuxt был выпущен в прошлом году. Теперь была выпущена директива изображения Angular ( NgOptimizedImage
), позволяющая перенести настройки оптимизации изображений по умолчанию в Angular.
Возможность
Angular — одна из ведущих платформ JavaScript, используемых сегодня разработчиками. Его используют более 50 тысяч источников, просканированных HTTPArchive на мобильных устройствах, и он может похвастаться почти 3 миллионами загрузок в неделю на NPM.
Глядя на показатели Core Web Vitals, процент источников Angular, соответствующих «хорошим» пороговым значениям LCP, все еще нуждается в доработке. В июне 2022 года только 18,74% сайтов Angular имели хороший LCP на мобильных устройствах. Поскольку изображения являются элементом LCP для более чем 70% веб-страниц на мобильных устройствах и настольных компьютерах, неоптимизированные изображения LCP могут быть одной из основных причин плохого LCP на Angular. веб-сайты.
Директива изображения Angular была разработана, чтобы помочь улучшить эти цифры.
MVP для директивы NgOptimizedImage
MVP директивы изображения Angular основан на уроках, извлеченных из компонентов изображения, которые Aurora создала на сегодняшний день, при адаптации дизайна к опыту рендеринга на стороне клиента Angular. Многие стандартные проблемы оптимизации изображений решаются следующими способами:
- Обеспечение сильных дефолтов.
- Выдача ошибок или предупреждений для обеспечения соответствия лучшим практикам.
Основные моменты дизайна заключаются в следующем:
Интеллектуальная отложенная загрузка
Изображения, которые невидимы для пользователя при загрузке страницы (например, изображения в нижней части страницы или скрытые изображения карусели), в идеале должны загружаться с отложенной загрузкой . Отложенная загрузка освобождает ресурсы браузера для загрузки другого важного текста, мультимедиа или сценариев. Большинство изображений некритичны и должны загружаться с отложенной загрузкой, но в 2021 году только 7,8% страниц использовали встроенную отложенную загрузку.
Директива Angular image по умолчанию загружает некритические изображения отложенно и охотно загружает только изображения, специально помеченные как
priority
. Это гарантирует, что большинство изображений демонстрируют оптимальное поведение при загрузке.Приоритизация критических изображений
Добавление подсказок ресурсов (например,
preload
илиpreconnect
) для определения приоритета загрузки критически важных изображений является рекомендуемой передовой практикой . Однако большинство приложений их не используют. Согласно Веб-альманаху 2021 года, только 12,7% мобильных страниц используют подсказки перед подключением и только 22,1% мобильных страниц используют подсказки предварительной загрузки.Директива image действует по двум направлениям, когда изображения помечаются как приоритетные.
- Он устанавливает приоритет выборки изображения на
"high"
, чтобы браузер знал, что ему следует загружать изображение с высоким приоритетом. - В режиме разработки проверка во время выполнения подтверждает, что была включена подсказка ресурса
preconnect
, соответствующая источнику изображения.
В режиме разработки директива также использует API PerformanceObserver для проверки того, что образу LCP присвоен ожидаемый
priority
. Еслиpriority
не отмечен, выдается ошибка, указывающая разработчику добавить атрибутpriority
в изображение LCP.В конечном итоге такое сочетание автоматизации и соответствия гарантирует, что образ LCP имеет подсказку
preconnect
, значение атрибутаfetchpriority
high
и не загружается отложенно.- Он устанавливает приоритет выборки изображения на
Оптимизированная конфигурация для популярных инструментов обработки изображений.
Приложениям Angular рекомендуется использовать CDN изображений , которые по умолчанию часто предоставляют услуги оптимизации.
Директива поощряет использование CDN изображений, предоставляя особенно привлекательный интерфейс для разработчиков (DX) для их настройки в приложении. Он поддерживает API-интерфейс загрузчика, который позволяет вам определить поставщика CDN и ваш базовый URL-адрес в вашей конфигурации. После настройки вам нужно только определить имя актива в разметке. Например,
// in module providers: provideImgixLoader('https://mysite.net/assets/') // in markup <img ngSrc="image.png" > <img ngSrc="image2.png" >
Это эквивалентно включению следующих тегов изображений и сокращает объем разметки, которую разработчики должны включать для каждого изображения.
<img src="https://mysite.net/assets/image.png"> <img src="https://mysite.net/assets/image2.png">
Директива image предоставляет встроенным загрузчикам оптимальную конфигурацию для самых популярных CDN изображений. Эти загрузчики автоматически форматируют URL-адреса изображений, чтобы гарантировать, что для каждой CDN используются рекомендуемый формат изображения и настройки сжатия.
Встроенные ошибки и предупреждения
Помимо вышеупомянутых встроенных оптимизаций, директива также имеет встроенные проверки, гарантирующие, что разработчики следовали рекомендуемым передовым методам разметки изображений. Директива изображения выполняет следующие проверки.
Неразмерные изображения: директива изображения выдает ошибку, если в разметке изображения не определены явные ширина и высота. Изображения неразмерного размера могут привести к смещению макета , что повлияет на показатель совокупного смещения макета ( CLS ) страницы. Чтобы избежать этого, рекомендуется указывать атрибуты
width
иheight
для изображений.Соотношение сторон: директива изображения выдает ошибку, чтобы сообщить разработчикам, если соотношение сторон
width
:height
, определенное в HTML, не близко к фактическому соотношению сторон визуализированного изображения. Это может привести к тому, что изображение на экране будет выглядеть искаженным. Это может произойти, если- Вы по ошибке определили неправильные размеры (ширину или высоту) или
- Если вы определили в CSS одно измерение в процентах, но не другое (например,
width: 100%
требуетсяheight: auto
, чтобы изображение увеличивалось в обоих измерениях).
Негабаритные изображения: если изображение не определяет
srcset
и внутреннее изображение значительно больше визуализированного изображения, директива отобразит предупреждение, предлагающее использовать атрибутыsrcset
иsizes
.Плотность изображения: директива выдаст ошибку, если вы попытаетесь включить в
srcset
изображение с плотностью пикселей более3x
. Дескрипторы выше2x
обычно не рекомендуются, поскольку это может привести к непредвиденным последствиям, вынуждающим мобильные устройства с высоким разрешением загружать огромные изображения. Более того, человеческий глаз на самом деле не может заметить значительную разницу выше 2x .
Проблемы
Адаптация стратегий оптимизации изображений для работы в рамках клиентской среды была основной задачей при разработке NgOptimizedImage
. По умолчанию в Next.js используется рендеринг на стороне сервера (SSR) или генерация статического сайта (SSG), а в Angular — рендеринг на стороне клиента (CSR). Несмотря на то, что Angular поддерживает библиотеку SSR — угловую/универсальную — большинство приложений Angular (~60%) используют CSR.
Директива изображения полностью создана для CSR и соответствует типичному варианту использования в приложениях Angular. Это наложило дополнительные ограничения, и команде пришлось переосмыслить способы создания конкретных оптимизаций для приложений CSR.
Некоторые из возникших проблем заключаются в следующем:
Поддержка подсказок по ресурсам
Предварительная загрузка критически важных ресурсов помогает браузеру обнаружить их раньше. Однако включение подсказок по ресурсам в приложения Angular затруднено, потому что:
Добавление вручную . Разработчикам сложно добавить подсказку о
preload
ресурса вручную. Angular использует один общий файл index.html для всего проекта или для всех маршрутов на веб-сайте. Таким образом,<head>
документа один и тот же для каждого маршрута (по крайней мере, во время обслуживания). Добавление любого указанияpreload
в<head>
будет означать, что ресурс будет предварительно загружен для всех маршрутов, даже там, где это не требуется. Таким образом, ручное добавление подсказокpreload
не рекомендуется.Автоматическое добавление во время рендеринга. Использование платформы для добавления подсказок предварительной загрузки в заголовок документа во время рендеринга в приложении CSR не помогает. Поскольку рендеринг происходит после загрузки и выполнения JavaScript,
<head>
будет отображаться слишком поздно, чтобы иметь какое-либо значение.В первой версии директивы комбинация подсказок
preconnect
иfetchpriority
служит для определения приоритета изображения вместоpreload
. Однако в настоящее время Aurora работает с командой Angular CLI, чтобы обеспечить автоматическое внедрение подсказок по ресурсам во время сборки — следите за обновлениями!Оптимизация размера и формата изображения на сервере
Поскольку приложения Angular обычно визуализируются на стороне клиента, изображения в файловой системе не могут быть сжаты во время запроса и предоставляются как есть. По этой причине рекомендуется использовать CDN изображений для сжатия изображений и преобразования их в современные форматы, такие как WebP или AVIF, по требованию.
Хотя директива не требует использования CDN изображений, настоятельно рекомендуется использовать их вместе с директивой, а ее встроенные загрузчики гарантируют использование правильных параметров конфигурации.
Влияние
Следующая демонстрация демонстрирует разницу, которую директива изображения Angular может повлиять на производительность изображения. Он сравнивает два сайта:
Веб-сайт 1: использует собственные элементы <img>
с изображениями, передаваемыми через Imgix CDN (с параметрами конфигурации по умолчанию).
Веб-сайт второй: используйте директиву image для всех изображений. Сюда также входят оптимизации, рекомендованные непосредственно предупреждениями или ошибками, выдаваемыми директивой.
Команда работала с партнерами, чтобы проверить влияние директивы image на производительность реальных корпоративных приложений Angular.
Одним из таких партнеров был Land's End . Ожидалось, что их сайт станет хорошей проверкой результатов, которые могут получить реальные приложения.
Лабораторное тестирование Lighthouse проводилось в их среде контроля качества до и после использования директивы изображения. На настольных компьютерах их медианное значение LCP снизилось с 12,0 с до 3,0 с, что означает улучшение показателя LCP на 75%. На мобильных устройствах медианное значение LCP снизилось с 20,2 до 12,0 с (улучшение на 40,6%).
Дорожная карта будущего
Это только первая часть дизайна директивы изображения Angular. В будущих версиях запланировано множество других функций, в том числе:
Улучшенная поддержка адаптивных изображений:
NgOptimizedImage
в настоящее время поддерживает использованиеsrcset
, но атрибутыsrcset
иsizes
необходимо указывать вручную для каждого изображения. В будущем директива сможет автоматически генерировать атрибутыsrcset
иsizes
.Автоматическое внедрение подсказок по ресурсам
Возможно, можно будет интегрироваться с Angular CLI для создания тегов предварительного подключения и предварительной загрузки для критических изображений LCP.
Поддержка Angular SSR
Версия MVP разработана с учетом ограничений Angular CSR, но также будет важно изучить решения по оптимизации изображений для Angular SSR (angular/universal).
Улучшения в работе с разработчиками
NgOptimizedImage
требует, чтобы атрибутыwidth
иheight
были указаны для каждого изображения. Однако указание их для каждого изображения может оказаться утомительным для некоторых разработчиков. В следующей итерации существует потенциал для улучшения опыта разработчиков следующим образом:- Поддержите дополнительный режим (аналогичный параметру макета изображения «
fill
» в Next.js ), который не требует явного определения ширины/высоты. - Использование интеграции CLI для автоматической установки ширины и высоты локальных изображений путем определения фактических размеров изображения.
- Поддержите дополнительный режим (аналогичный параметру макета изображения «
Заключение
Директива изображения Angular будет доступна разработчикам поэтапно, начиная с предварительной версии для разработчиков v14.2.0. Попробуйте NgOptimizedImage
и оставьте отзыв!
Особая благодарность Кэти Хемпениус и Алексу Кастлу за их вклад.