Ques/Help/Req Как работает Next Image в Next.js

XakeR

Member
Регистрация
13.05.2006
Сообщения
1 912
Реакции
0
Баллы
16
Местоположение
Ukraine
Если вы работали с Next.js, скорее всего, вы сталкивались с компонентом Next Image. Это беззаботное решение для оптимизации изображений не только поддерживает современные форматы, такие как webp и avif, но также генерирует несколько версий, адаптированных под различные размеры экранов.

Чтобы воспользоваться этой волшебством, просто добавьте следующий код на вашу страницу:

import Image from ‘next/image’; export default function Page() { return ( <Image src=»/profile.png» width={500} height={500} alt=»Picture of the author» /> ); }

Однако, как и в случае с любой магией, за этим безупречным функционированием стоит твердая основа трудолюбия. В этой статье мы собираемся исследовать, как работает Next Image, и развеять некоторые распространенные заблуждения, связанные с ним.

Архитектура ядра​


Базовая архитектура next/image в основном состоит из трех компонентов:

  1. Компонент React Next Image.
  2. API изображений.
  3. Оптимизатор изображений.

Как работает Next Image в Next.js0


Компонент React​


Основная функция компонента — генерировать правильный HTML-код изображения на основе предоставленных свойств и создавать несколько URL-адресов для заполнения атрибутов srcset и src. Вот пример вывода компонента Next Image:

<img alt=»Example» loading=»lazy» width=»500″ height=»500″ decoding=»async» data-nimg=»1″ style=»color:transparent» srcset=»/_next/image?url=%2Fimages%2Fexample.jpg&w=640&q=75 1x, /_next/image?url=%2Fimages%2Fexample.jpg&w=1080&q=75 2x» src=»/_next/image?url=%2Fimages%2Fexample.jpg&w=1080&q=75″ >

Давайте ближе рассмотрим сгенерированный URL:

/_next/image?url=/images/example.jpg&w=640&q=75

Закодированный URL принимает два параметра: w (ширина) и q (качество), которые становятся более понятными в расшифрованной версии. Вы можете заметить, что нет атрибута h (высота), но об этом мы поговорим позже, в данной статье.

API изображений​


API изображений Next Image служит прокси для изображений, подобно IPX. Он выполняет следующие задачи:

  1. Принимает URL изображения, ширину и качество.
  2. Проверяет параметры.
  3. Определяет политику кэширования.
  4. Обрабатывает изображение.
  5. Предоставляет изображение в формате, поддерживаемом браузером пользователя

По мере того, как все начинает проясняться, давайте кратко обсудим последний кусочек головоломки, прежде чем сделать некоторые выводы из этой структуры.

Оптимизатор изображений​


Next Image использует различные библиотеки для оптимизации изображений — Sharp или Squoosh — в зависимости от определенных условий:

  1. Sharp — быстрая и эффективная модуль оптимизации изображений для Node.js, которая использует нативную библиотеку libvips.
  2. Squoosh — полностью основанное на Node решение для оптимизации изображений. Оно медленнее, но не требует установки дополнительных библиотек на компьютер. По этой причине Sharp рекомендуется для использования в производственной среде, в то время как Squoosh используется по умолчанию в локальных средах.

Я советую также использовать Sharp в локальных средах. В то время как и Sharp, и Squoosh оптимизируют изображения похожим образом, алгоритмы сжатия Sharp могут привести к деградации цветов по сравнению с Squoosh. Это может привести к визуально различному поведению между производственной и локальной средами, особенно при попытке совмещения цвета фона изображения с цветом фона страницы.

Типы выводов Next Image​


Поняв основную архитектуру next/image, мы можем развенчать распространенные заблуждения и получить больше понимания о том, как эффективно использовать его.

next/image не обрезает изображения

Распространенное заблуждение среди разработчиков заключается в том, что next/image может обрезать их изображения. Это недоразумение возникает потому, что вы можете передать ширину, высоту и свойство fill компоненту, создавая впечатление, что изображение было обрезано. На самом деле это не так. Компонент Next Image в основном требует ширины и высоты для присвоения тегу img и предотвращения сдвигов макета.

Как работает Next Image в Next.js1


Как мы уже обсуждали, API изображений не принимает параметр высоты, что означает, что в настоящее время невозможно изменить соотношение сторон исходного изображения. Если вы не используете свойство fill, изображение просто будет растягиваться или сжиматься в случае несоответствия ширины и высоты.

Однако, если вы используете TailwindCSS, он ведет себя по-другому из-за своего глобального правила CSS по умолчанию:

img, video { max-width: 100%; height: auto; }

Это делает проблемы смещения макета более труднообнаружимыми.

Ширина отображаемого изображения ≠ загруженная ширина изображения

Еще одна потенциальная точка путаницы заключается в том, что свойство width, переданное в next/image, не представляет фактическую ширину, к которой будет изменено изображение. Как мы отметили в примере в начале статьи, передача width={500} в компонент приведет к изменению ширины изображения до 640 пикселей, как видно по сгенерированному URL:

/_next/image?url=/images/example.jpg&w=640&q=75

Если вы ожидаете, что версия x2 retina будет использовать ширину изображения 1000 пикселей или 1280 пикселей, то вас ждет сюрприз. Фактическая используемая ширина составит 1080 пикселей. Естественно, может возникнуть вопрос, откуда берутся эти числа.

Как работает Next Image в Next.js2


Next.js изменяет размеры изображений до ближайшего размера из массивов deviceSizes и imageSizes, которые вы можете определить в файле next.config.js. По умолчанию они выглядят так:

module.exports = { images: { deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], imageSizes: [16, 32, 48, 64, 96, 128, 256, 384], }, };

Важно отметить, что использование конфигурации по умолчанию может негативно сказаться на производительности, приводя к снижению показателей в Page Speed Insights от Lighthouse. Это особенно заметно, когда вы пытаетесь отобразить большие изображения на странице. Например, если вы хотите отобразить изображение с шириной 1250 пикселей, фактическая загруженная ширина изображения будет 1920 пикселей. Разрыв между требуемым размером и фактическим загруженным размером становится еще больше для версий x2 retina, так как они будут изменены до 3840 пикселей. Однако, вы можете исправить это, добавив больше размеров в массивы deviceSizes или imageSizes (документация).

Как работает Next Image в Next.js3

Оптимизация изображений может использоваться без компонента next/image

С пониманием основной архитектуры легко видеть, что можно использовать Image API без обязательного использования next/image. Существуют несколько сценариев, в которых это может быть полезно.

Middle/Senior Backend node.js Developer (МТС еСпортс) МТС, Удалённо, По итогам собеседования tproger.ru Вакансии на tproger.ru

Во-первых, вы можете рендерить оптимизированные изображения внутри холста. Независимо от того, загружаете ли вы изображения на холст из внешних источников или из локального хранилища, вы можете передать правильный URL в API и он будет работать без сбоев.

Кроме того, вы можете использовать его для оптимизации OG-изображений или создать собственный компонент на основе тега <picture> для лучшего управления художественным направлением.

Image API находится по адресу /_next/image и принимает всего три дополнительных параметра: URL, ширина (w) и качество (q).

/_next/image?url=

Помните, что параметр width проверяется API и может быть только числом, полученным из конфигурации deviceSizes или imageSizes.

Используйте import для локальных изображений

С помощью next/image есть два способа загрузки локальных изображений:

import Image from ‘next/image’; import profileImg from ‘./profile.jpg’; export default function Page() { return ( <> {/* Using absolute path */} <Image src=»/profile.png» width={500} height={500} alt=»Picture of the author» /> {/* Using imported image via relative path */} <Image src={profileImg} alt=»Picture of the author» /> </> ); }

Использование абсолютного пути обычно применяется при работе с локальными изображениями в примерах, учебных пособиях или даже в проектах с открытым исходным кодом. Легко подумать, что, за исключением автоматического назначения ширины/высоты, разницы нет. Однако есть разница. При доступе к изображениям по абсолютному пути из публичной папки Next.js придерживается политики кэширования сервера назначения, которая по умолчанию устанавливает политику кэширования на 30 дней, вместо public, max-age=31536000, immutable. Использование кэширования на 30 дней для изображений может значительно ухудшить показатель Lighthouse.

Понимание размеров и техники 100vw

Компонент next/image принимает свойство, известное как «sizes», аналогичное атрибуту sizes в html img. Однако, в соответствии с другими аспектами, о которых мы говорили, оно также выполняет некоторые уникальные операции. Атрибут «sizes» работает вместе с «srcset» и принимает список условий для браузера и ширин изображения для их активации. Если вы не знакомы с этим, рекомендую ознакомиться с этой документацией и этим примером в codesandbox. Вот пример изображения, использующего «sizes»:

<img srcset=»/img/html/vangogh-sm.jpg 120w, /img/html/vangogh.jpg 193w, /img/html/vangogh-lg.jpg 278w» sizes=»(max-width: 710px) 120px, (max-width: 991px) 193px, 278px»>

Давайте углубимся в детали для лучшего понимания. Когда вы используете Next Image без указания свойства ‘sizes’, ваш ‘srcset’ будет включать два URL: один для стандартной версии (x1) и другой для версии Retina (x2). При такой настройке, браузер всегда выберет версию Retina при использовании на устройстве с Retina-дисплеем. Это предпочтение возникает из-за использования синтаксиса 1x и 2x внутри ‘srcset’.

<img srcset=» /_next/image?url=%2Fimages%2Fexample.jpg&w=640&q=75 1x, /_next/image?url=%2Fimages%2Fexample.jpg&w=1080&q=75 2x » />

Браузер фактически интерпретирует это как: «Загрузи этот URL для плотности пикселей 2x, а этот другой для плотности пикселей 1x». Таким образом, если у вас есть дизайн, в котором версия изображения на настольном компьютере меньше, чем на мобильном телефоне или планшете, браузер всегда будет загружать более крупную версию с помощью стандартного синтаксиса Next Image. К сожалению, это может привести к неоптимальной производительности и более низкому показателю Lighthouse.

Однако есть способ указать браузеру загружать изображения на основе подходящей ширины. Вместо указания параметров 1x, 2x для URL в ‘srcset’, вы указываете ширину изображения. Например, вот инструкции для браузера:

<img srcset=» /_next/image?url=%2Fimages%2Fexample.jpg&w=640&q=75 640w, /_next/image?url=%2Fimages%2Fexample.jpg&w=1080&q=75 1080w » />

В этом случае браузер выбирает наиболее подходящее изображение для текущего размера, используемого на странице. Если у мобильного изображения ширина составляет 600 пикселей (1200 пикселей для Retina), то будет выбрана версия с шириной 1080w. Тем временем, если у изображения для настольного компьютера ширина составляет всего лишь 300 пикселей (600 пикселей для Retina), браузер выбирает версию с шириной 640w.

Преимущество такого подхода заключается в загрузке наиболее подходящих изображений для текущего размера экрана, что улучшает производительность благодаря уменьшению размера изображения. Теперь, когда мы понимаем преимущества, мы можем применить эту стратегию с помощью Next Image, используя трюк с 100vw. Хотя вы не можете напрямую указать Next Image использовать параметры ширины (w) рядом с URL вместо опций плотности пикселей (1x), вы можете применить обходной путь, основанный на том, как кодируется Next Image:

Если ваш атрибут ‘sizes’ содержит значения vw, он будет сохранять только те размеры, которые больше наименьшего размера устройства (по умолчанию 640), умноженного на процент (100vw = 1, 50vw = 0.5). Указав 100vw, вы получите 8 URL-адресов.

Если ваше свойство ‘sizes’ содержит числа, отличные от vw, ваш ‘srcset’ будет содержать ВСЕ РАЗМЕРЫ (т.е. все возможные комбинации deviceSizes и imageSizes), в результате получится 16 URL-адресов.

Для наглядности давайте рассмотрим сгенерированный код для 100vw:

<img sizes=»100vw» srcset=» /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=640&q=75 640w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=750&q=75 750w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=828&q=75 828w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=1080&q=75 1080w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=1200&q=75 1200w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=1920&q=75 1920w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=2048&q=75 2048w, /_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=3840&q=75 3840w » src=»/_next/image?url=%2F_next%2Fstatic%2Fmedia%2Fexample.6be618a3.jpg&w=3840&q=75″ />

Если вы указываете значение px внутри ‘sizes’ (например, (max-width: 1024px) 800px, 300px), список URL-адресов расширяется еще больше, достигая 16 в конфигурации по умолчанию. В идеале я предпочел бы генерировать 4 URL-адреса для конкретного изображения, подобно другим фреймворкам, вместо раздутия HTML-кода ненужными вариантами, ни один из которых, вероятно, не будет идеально подходить для моих потребностей.

Это обсуждение подчеркивает ключевой момент: чтобы заполнить ‘srcset’ большим количеством версий для лучшей производительности на разных разрешениях, достаточно установить ‘sizes’ на 100vw. Этот трюк приводит к созданию URL-адресов для 8 размеров, начиная с 640px.

Однако, поскольку этот метод может значительно увеличить размер вашего HTML-кода, особенно если вы добавили дополнительные imageSizes или deviceSizes, рекомендуется тщательно применять этот подход.

Хотя я могу только предполагать точные причины такой архитектуры, я предполагаю, что для крупномасштабных проектов с разными соотношениями изображений, используемых во многих разных местах, этот подход генерации средних версий может быть полезным. Эти версии могут подходить для большинства сценариев и, возможно, чаще попадать в кэш, при этом сохраняя простоту использования.

Результаты​


Хотя Next Image упрощает управление изображениями и предоставляет значительные преимущества, он мог бы воспользоваться дополнительными функциями, такими как продвинутое обрезание и точное изменение размера, аналогичные решениям от сторонних разработчиков. Введение специализированного компонента для тонкой настройки художественного направления также было бы полезным. Я особенно оценил бы автоматический метод генерации четырех версий изображений с размерами 0.25x, 0.5x, 1x и 2x от указанной ширины.

Тем не менее, для большинства случаев использования опыт разработчика и эффективность Next Image будут более чем достаточными.
 
198 196Темы
635 167Сообщения
3 618 416Пользователи
artvladimir2004Новый пользователь
Верх