Как самостоятельно разместить приложение Next.js
При развёртывании вашего приложения Next.js вы можете настроить обработку различных функций в зависимости от вашей инфраструктуры.
🎥 Видео: Подробнее о самостоятельном размещении Next.js → YouTube (45 минут).
Оптимизация изображений
Оптимизация изображений через next/image
работает при самостоятельном размещении без дополнительной конфигурации при развёртывании с помощью next start
. Если вы предпочитаете использовать отдельный сервис для оптимизации изображений, вы можете настроить загрузчик изображений.
Оптимизация изображений может использоваться с статическим экспортом путём определения пользовательского загрузчика изображений в next.config.js
. Обратите внимание, что изображения оптимизируются во время выполнения, а не во время сборки.
Полезно знать:
- В системах Linux на основе glibc для оптимизации изображений может потребоваться дополнительная настройка для предотвращения чрезмерного использования памяти.
- Узнайте больше о поведении кэширования оптимизированных изображений и о том, как настроить TTL.
- Вы также можете отключить оптимизацию изображений и сохранить другие преимущества использования
next/image
. Например, если вы оптимизируете изображения отдельно.
Middleware
Middleware работает при самостоятельном размещении без дополнительной конфигурации при развёртывании с помощью next start
. Поскольку для работы middleware требуется доступ к входящему запросу, она не поддерживается при использовании статического экспорта.
Middleware использует Edge runtime, подмножество всех доступных API Node.js, чтобы обеспечить низкую задержку, так как может выполняться перед каждым маршрутом или ресурсом в вашем приложении. Если это не требуется, вы можете использовать полный Node.js runtime для выполнения middleware.
Если вам нужно добавить логику (или использовать внешний пакет), требующую всех API Node.js, вы можете перенести эту логику в layout как Server Component. Например, проверка заголовков и перенаправление. Вы также можете использовать заголовки, куки или параметры запроса для перенаправления или перезаписи через next.config.js
. Если это не подходит, вы можете использовать custom server.
Переменные окружения
Next.js поддерживает переменные окружения как во время сборки, так и во время выполнения.
По умолчанию переменные окружения доступны только на сервере. Чтобы сделать переменную окружения доступной в браузере, она должна иметь префикс NEXT_PUBLIC_
. Однако эти публичные переменные будут встроены в JavaScript-бандл во время next build
.
Вы можете безопасно читать переменные окружения на сервере во время динамического рендеринга.
import { connection } from 'next/server'
export default async function Component() {
await connection()
// cookies, headers и другие Dynamic API
// также переключат на динамический рендеринг, что означает
// эта переменная окружения вычисляется во время выполнения
const value = process.env.MY_VALUE
// ...
}
import { connection } from 'next/server'
export default async function Component() {
await connection()
// cookies, headers и другие Dynamic API
// также переключат на динамический рендеринг, что означает
// эта переменная окружения вычисляется во время выполнения
const value = process.env.MY_VALUE
// ...
}
Это позволяет использовать единый Docker-образ, который можно развертывать в разных окружениях с разными значениями.
Полезно знать:
- Вы можете выполнять код при запуске сервера с помощью функции
register
.- Мы не рекомендуем использовать опцию runtimeConfig, так как она не работает с режимом standalone output. Вместо этого рекомендуем постепенно переходить на App Router.
Кэширование и ISR
Next.js может кэшировать ответы, сгенерированные статические страницы, результаты сборки и другие статические ресурсы, такие как изображения, шрифты и скрипты.
Кэширование и ревалидация страниц (с помощью Incremental Static Regeneration) используют общий кэш. По умолчанию этот кэш хранится в файловой системе (на диске) вашего сервера Next.js. Это работает автоматически при самостоятельном размещении как с Pages Router, так и с App Router.
Вы можете настроить расположение кэша Next.js, если хотите сохранять кэшированные страницы и данные в долговременное хранилище или делиться кэшем между несколькими контейнерами или экземплярами вашего приложения Next.js.
Автоматическое кэширование
- Next.js устанавливает заголовок
Cache-Control
в значениеpublic, max-age=31536000, immutable
для действительно неизменяемых ресурсов. Это нельзя переопределить. Эти неизменяемые файлы содержат SHA-хэш в имени файла, поэтому их можно безопасно кэшировать бессрочно. Например, Static Image Imports. Вы можете настроить TTL для изображений. - Incremental Static Regeneration (ISR) устанавливает заголовок
Cache-Control
в значениеs-maxage: <revalidate in getStaticProps>, stale-while-revalidate
. Время ревалидации определяется в вашей функцииgetStaticProps
в секундах. Если вы установитеrevalidate: false
, продолжительность кэширования по умолчанию составит один год. - Динамически рендеренные страницы устанавливают заголовок
Cache-Control
в значениеprivate, no-cache, no-store, max-age=0, must-revalidate
, чтобы предотвратить кэширование пользовательских данных. Это применяется как к App Router, так и к Pages Router. Это также включает Draft Mode.
Статические ресурсы
Если вы хотите размещать статические ресурсы на другом домене или CDN, вы можете использовать конфигурацию assetPrefix
в next.config.js
. Next.js будет использовать этот префикс при загрузке JavaScript или CSS файлов. Разделение ресурсов на другой домен имеет недостаток в виде дополнительного времени, затрачиваемого на разрешение DNS и TLS.
Настройка кэширования
По умолчанию сгенерированные кэшированные ресурсы хранятся в памяти (по умолчанию 50 МБ) и на диске. Если вы размещаете Next.js с помощью платформы оркестрации контейнеров, такой как Kubernetes, каждый pod будет иметь свою копию кэша. Чтобы предотвратить отображение устаревших данных, так как кэш по умолчанию не является общим между pod, вы можете настроить обработчик кэша Next.js и отключить кэширование в памяти.
Чтобы настроить расположение кэша ISR/Data Cache при самостоятельном размещении, вы можете настроить пользовательский обработчик в файле next.config.js
:
module.exports = {
cacheHandler: require.resolve('./cache-handler.js'),
cacheMaxMemorySize: 0, // отключить кэширование в памяти по умолчанию
}
Затем создайте cache-handler.js
в корне вашего проекта, например:
const cache = new Map()
module.exports = class CacheHandler {
constructor(options) {
this.options = options
}
async get(key) {
// Это может храниться где угодно, например в долговременном хранилище
return cache.get(key)
}
async set(key, data, ctx) {
// Это может храниться где угодно, например в долговременном хранилище
cache.set(key, {
value: data,
lastModified: Date.now(),
tags: ctx.tags,
})
}
async revalidateTag(tags) {
// tags - это строка или массив строк
tags = [tags].flat()
// Перебираем все записи в кэше
for (let [key, value] of cache) {
// Если теги значения включают указанный тег, удаляем эту запись
if (value.tags.some((tag) => tags.includes(tag))) {
cache.delete(key)
}
}
}
// Если вы хотите иметь временный кэш в памяти для одного запроса, который сбрасывается
// перед следующим запросом, вы можете использовать этот метод
resetRequestCache() {}
}
Использование пользовательского обработчика кэша позволит вам обеспечить согласованность между всеми pod, на которых размещено ваше приложение Next.js. Например, вы можете сохранять кэшированные значения где угодно, например в Redis или AWS S3.
Полезно знать:
revalidatePath
- это удобный слой поверх тегов кэша. ВызовrevalidatePath
вызовет функциюrevalidateTag
с особым тегом по умолчанию для указанной страницы.
Кэш сборки
Next.js генерирует ID во время next build
для идентификации версии вашего приложения. Одна и та же сборка должна использоваться и запускаться в нескольких контейнерах.
Если вы пересобираете для каждого этапа вашего окружения, вам нужно сгенерировать постоянный ID сборки для использования между контейнерами. Используйте команду generateBuildId
в next.config.js
:
module.exports = {
generateBuildId: async () => {
// Это может быть что угодно, например последний git-хэш
return process.env.GIT_HASH
},
}
Расхождение версий
Next.js автоматически устраняет большинство случаев расхождения версий и автоматически перезагружает приложение для получения новых ресурсов при обнаружении. Например, если есть несоответствие в deploymentId
, переходы между страницами будут выполнять hard navigation вместо использования предварительно загруженного значения.
При перезагрузке приложения может произойти потеря состояния приложения, если оно не предназначено для сохранения между переходами по страницам. Например, использование состояния URL или локального хранилища сохранит состояние после перезагрузки страницы. Однако состояние компонентов, такое как useState
, будет потеряно при таких переходах.
Потоковая передача и Suspense
App Router Next.js поддерживает потоковую передачу ответов при самостоятельном размещении. Если вы используете Nginx или аналогичный прокси, вам нужно настроить его для отключения буферизации, чтобы включить потоковую передачу.
Например, вы можете отключить буферизацию в Nginx, установив X-Accel-Buffering
в no
:
module.exports = {
async headers() {
return [
{
source: '/:path*{/}?',
headers: [
{
key: 'X-Accel-Buffering',
value: 'no',
},
],
},
]
},
}
Частичный предварительный рендеринг
Частичный предварительный рендеринг (экспериментальный) работает по умолчанию с Next.js и не является функцией только для CDN. Это включает развёртывание как сервера Node.js (через next start
) и использование с Docker-контейнером.
Использование с CDN
При использовании CDN перед вашим приложением Next.js страница будет включать заголовок ответа Cache-Control: private
при доступе к динамическим API. Это гарантирует, что результирующая HTML-страница помечена как не кэшируемая. Если страница полностью предварительно рендерится в статический вид, она будет включать Cache-Control: public
, чтобы разрешить кэширование страницы на CDN.
Если вам не нужна смесь статических и динамических компонентов, вы можете сделать весь маршрут статическим и кэшировать выходной HTML на CDN. Эта автоматическая статическая оптимизация является поведением по умолчанию при запуске next build
, если динамические API не используются.
По мере перехода Partial Prerendering в стабильную версию мы предоставим поддержку через Deployment Adapters API.
after
after
полностью поддерживается при самостоятельном размещении с next start
.
При остановке сервера убедитесь в плавном завершении работы, отправляя сигналы SIGINT
или SIGTERM
и ожидая. Это позволяет серверу Next.js дождаться завершения ожидающих функций обратного вызова или промисов, используемых внутри after
.