Прежде чем мы начнем рассматривать методы оптимизации изображений, которые Next.js предоставляет из коробки, давайте договоримся об одном … Я постараюсь избегать всех тех модных терминов, которые сегодня без ума от мира производительности, например такие как Core Web Vitals, Самый большой Contentful Paint, Cumulative Layout Shift, First Input Delay и т. д. Эти термины хорошо описаны экспертами в нише производительности, например, в книге Адди Османи об оптимизации изображений. И я сосредоточусь больше на практической стороне оптимизации изображений в контексте Next.js.
Вы знаете, почему компании тратят тысячи долларов на оптимизацию производительности? Ответ прост — потому что эффективность напрямую зависит от того, отдают ли клиенты свои деньги компаниям или нет.
Типичный клиент хочет получить услугу или продукт как можно быстрее, а сайт, который удовлетворяет его потребности быстрее других, получает больше продаж, подписок, конверсий и, как следствие, больше доходов.
Золотое правило оптимизации производительности
Золотое правило любой оптимизации производительности для меня можно описать просто: дать пользователям то, что они хотят, в кратчайшие сроки или предоставить временную альтернативу, например некоторую полезную информацию, возможность развлечения или свободу делать что-либо еще в ожидании. для запрошенного результата.
Предоставьте пользователям то, что они хотят, в кратчайшие сроки или предоставьте временную альтернативу.
Если максимально быстрое удовлетворение потребностей пользователя обеспечивается прямыми мерами по оптимизации производительности, например ускорением работы сервера, то предоставление пользователю временной альтернативы дает только временное облегчение при выполнении запрошенного действия, например, отображение индикатор прогресса. Последнее значительно улучшает взаимодействие с пользователем (UX).
Поэтому в этом посте я логически разделю методы оптимизации производительности изображения на два типа, такие как оптимизация загрузки изображения и предоставление временной альтернативы.
Начать с примеров
Полагаю, вы знакомы с React и Next.js. Если вам нужно освежить свои знания о Next.js, пожалуйста, сначала ознакомьтесь с моим Руководством по Next.js .
Я подготовил несколько примеров, которые вы можете использовать для экспериментов с Next.js Images.
Начнем с клонирования моего проекта примеров из Github:
Откройте проект в своей среде IDE и загляните в папку / pages . Страницы Next.js, расположенные в этой папке, названы в соответствии с соответствующими методами оптимизации изображений.
Запустите приложение:
пряжа
Затем откройте http: // localhost: 3000 в Chrome, чтобы увидеть список доступных примеров. Мы будем идти шаг за шагом сверху вниз.
Собственный Тег
Первый пример демонстрирует использование собственного тега HTML просто для сравнения его с другими примерами.
Все изображения, используемые в этом сообщении, обслуживаются из папки / public включая sunset1.jpg . Обратите внимание, что Next.js заставляет использовать свой компонент вместо собственного тега путем включения соответствующей проверки линтера в сборку приложения процесса, поэтому для создания приложения мне пришлось отключить проверку, добавив «@ next / next / no-img-element»: «off» в раздел правил конфигурации .eslintrc config.
Давайте запустим пример и откроем его в Chrome с активированными Chrome Dev Tools http: // localhost: 3000 / native-img-tag.
Неоптимизированные изображения Next.js
Файл /pages/unoptimized-images.js содержит пример настроек компонента Next.js Image, которые имитируют поведение тега .
Мы можем запустить код, открыв в браузере http: // localhost: 3000 / unoptimized-images.
// Импортировать как компонент React.
импортировать SunsetImage из '../public/sunset1.jpg';
// Используем внешнее изображение.
Но если вы используете внешние изображения, не забудьте добавить домен изображения через конфигурацию Next. Иначе не пойдет.
Пора оптимизировать изображения. Я сделал это в /pages/better-format-size-resolution.js где я включил оптимизацию изображения по умолчанию, удалив следующее свойство:
Next изменил формат изображения с JPG на WebP, потому что мой браузер поддерживает этот современный формат, который демонстрирует лучшее сжатие.
Эй, подождите … Почему он показывает изображения шириной 640 пикселей, если мы запрашивали 600 пикселей? Это потому, что это значение настраивается через конфигурацию Next.js. Точки останова по умолчанию:
Next использует ближайшее определенное значение ширины для создания изображения, поэтому, если вы знаете точное разрешение изображений в вашем приложении, не стесняйтесь добавлять их ширину в список, чтобы сгенерированные разрешения соответствовали запрошенным разрешениям как можно ближе насколько возможно. И я добавлю 600 в список, чтобы добиться лучших результатов оптимизации:
Вы, вероятно, знаете, что можно улучшить разрешение изображения в зависимости от размера устройства (области просмотра), используя и функции HTML.
Компонент изображения Next.js использует свойство srcset для адаптивного обслуживания изображений.
До сих пор мы использовали фиксированный макет для изображений, который работал аналогично собственному тегу . Теперь мы собираемся улучшить наши изображения, добавив альтернативные варианты изображений для разных размеров устройств. Next сделает это за нас автоматически, если мы установим свойство макета на отзывчивый .
Если мы откроем этот пример в браузере http: // localhost: 3000 / response-images, мы увидим свойство srcset со всеми возможными вариантами, добавленными к результирующему изображению:
sizesunset1.jpg — 16,5 КБ — webp — 750 × 563
Загружаются и отображаются только те четыре изображения, которые лучше соответствуют размеру моего окна просмотра.
Работая над примерами, я заметил неприятную проблему, вызванную предопределенными стилями компонентов изображения. Я хотел поместить компоненты изображения в контейнер Flexbox, чтобы отображать их в столбце, но стили конфликтовали, и изображения становились невидимыми. Чтобы обойти эту проблему, мне пришлось сообщить об ошибке и переключиться на контейнер CSS Grid.
Ленивая загрузка
Компонент Next.js Image по умолчанию включает отложенную загрузку, что означает, что приложение загружает и отображает только те изображения, которые в данный момент находятся на экране пользователя, уменьшая объем данных, загружаемых пользователем. Это полезно не только для конечного пользователя, но и для сервера, поскольку ему не нужно запускать создание изображений для изображений, которые могут никогда не понадобиться.
Поскольку отложенная загрузка является настройкой по умолчанию для компонента "Следующее изображение", давайте просто удалим loading = "eager" чтобы заставить его работать.
Запустите приложение и откройте пример отложенной загрузки http: // localhost: 3000 / lazy-loading.
Предварительная загрузка изображений
Иногда может потребоваться предварительная загрузка наиболее важных изображений заранее. Компонент Next.js Image может устанавливать приоритет загрузки изображения через priority = {true} .
На скриншоте ниже, mountains2.jpg расположенный внизу страницы, загружается раньше других из-за повышенного приоритета.
CDN и услуги преобразования изображений
Иногда для преобразования и доставки изображений полезно использовать стороннюю службу изображений. Основные причины:
изображение обслуживается из географически ближайшего центра обработки данных с использованием сети CDN,
облачный провайдер может иметь больше вариантов преобразования,
вам не нужен высокопроизводительный процессор для обработки изображения и расширенное дисковое пространство для их хранения.
Компонент Next.js Image поддерживает несколько облачных провайдеров из коробки, установив свойство loader компонента.
К сожалению, Next.js не имеет встроенной предустановки интеграции для службы Uploadcare по историческим причинам, но, поскольку это хороший вариант, я решил показать вам, как создать собственный загрузчик для службы Uploadcare в моем следующая статья. Оставайтесь с нами!
Обеспечение временной альтернативы
Для изображений временной альтернативой обычно является индикатор загрузки, размытая версия исходного изображения или изображение более низкого качества. Временная замена изображения предотвращает скачки содержимого страницы вверх и вниз и указывает на то, что изображение загружается.
Next может автоматически сгенерировать размытое изображение-заполнитель или предоставить нам собственное изображение-заполнитель.
Заполнитель по умолчанию
Next может сгенерировать заполнитель на основе изображения, но он требует, чтобы изображение было импортировано статически.
// страницы / default-placeholder-image.js
импортировать sunset1 из '../public/sunset1.jpg';
Этот код дает следующий приятный эффект:
Здесь заполнитель представляет собой встроенное изображение с малым разрешением, следующее за исходными цветами изображения и представленное строка вроде этой: «data: image / jpeg; base64…».
Запустите приложение примеров и посмотрите, как оно работает здесь http: // localhost: 3000 / default-placeholder-image
Пользовательский заполнитель
Чтобы показать, как добавить собственное изображение-заполнитель, я создал серое изображение размером 1 × 1 пиксель в кодировке base64 через службу PNG Pixel и передал его компонентам изображения через свойство blurDataURL :
На странице http: // localhost: 3000 / custom-placeholder-image это выглядит так:
Ограничения компонентов изображения
Ничто в мире программирования не является идеальным на 100%, и компонент Image тоже нуждается в улучшении. Я хотел бы вкратце упомянуть, что я хотел бы улучшить.
Трудно настроить стили CSS по умолчанию
Этот код добавит класс image в тег а не в его родительскую оболочку
отображаемую компонентом Image, поэтому ее трудно переопределить. стили.
А прохождение свойства стиля вообще не поддерживается.
Конфликты с Flexbox
Сначала я поместил свои изображения в контейнер Flexbox, но затем мне пришлось заменить его CSS Grid, потому что я обнаружил ошибку next / image. Оказалось, что это известная проблема, и разработчики Next.js в настоящее время работают над решением.
Повышенная нагрузка на сервер и использование дискового пространства
Хотя создание образа во время выполнения имеет свои преимущества, это ресурсоемкая операция.
Генерация изображения — это процесс вычисления, означающий, что он активно использует ЦП и ОЗУ. Если вы загружаете страницу с десятью изображениями, расположенными в видимой части страницы в первый раз (без кеширования; без включенной ленивой загрузки), вы запускаете десять вычислительных процессов на сервере. Поэтому, если вам нужен loading = ”eager”, используйте его осторожно, чтобы избежать ненужной нагрузки на сервер.
Еще одна вещь, на которую я хотел бы обратить внимание, — это использование дискового пространства. Когда пользователь загружает страницу с компонентом Next.js Image в первый раз, Next генерирует изображение подходящего размера и формата. Полученное изображение сохраняется в кеше файловой системы, который находится в папке проекта ./ next / cache / images . Когда пользователь загружает страницу в следующий раз, изображение обслуживается непосредственно из кеша, что экономит время процессора. Однако, если в вашем приложении много разных изображений, например, с адаптивными вариантами, вам необходимо отслеживать использование дискового пространства, чтобы кеш-память не занимала все доступное дисковое пространство.
Однако, как я упоминал ранее, проблемы как с использованием диска, так и с нагрузкой на сервер можно решить, переключившись на внешнюю службу преобразования образов и CDN.
Плюсы и минусы
Позвольте мне кратко резюмировать, что мне нравится в компоненте Next.js Image и что может быть лучше.
Плюсы
Минусы
Более компактное изображение формат по умолчанию
Трудно переопределить стили CSS по умолчанию
Меньший размер изображения по умолчанию
Конфликты с Flexbox
Лучшее разрешение изображения по умолчанию
Повышенная нагрузка на сервер и использование дискового пространства (если используется неразумно)
Ленивая загрузка изображений по умолчанию
Поддержка адаптивных изображений
Поддержка предварительной загрузки изображения
Поддержка заполнителей изображений
Плюсы и минусы компонента Next.js Image
Выводы
Выбирая альтернативу собственному тегу HTML, вы должны принять тот факт, что кто-то заранее определил для него стили, которые не всегда легко настроить.
Если вы не можете оптимизировать загрузку изображений для по какой-то причине подумайте о добавлении временной замены образа, потому что это значительно улучшает UX.
С next / image образы не создаются на этапе сборки, что ускоряет развертывание приложения, но генерация по-прежнему потребляет те же ресурсы и компьютер времени во время выполнения.
Я лично считаю, что Next.js находится на правильном пути со своим изображением UX и улучшениями производительности. Это то, чего мне не хватает в собственном теге HTML .
Внешние CDN и службы преобразования изображений могут повысить производительность и сделать ваши изображения более гибкими. Кстати, мой следующий пост будет об интеграции Next.js и Uploadcare через специальный загрузчик для компонента Next.js Image. Подпишитесь на обновления блога ниже, чтобы оставаться в курсе!
Что дальше
Вы можете просмотреть официальную документацию next / image или примеры компонентов изображения, если вы ищете что-то конкретное, чего не нашли в моем сообщении.
Встроенная оптимизация изображений Next.js — не единственный способ повысить производительность изображений в Next, поэтому вы можете проверить проекты cyrilwanner / next-optimized-images и twopluszero / next-images, если хотите рассмотреть альтернативные решения.