Режимы рендеринга
Nuxt поддерживает разные режимы рендеринга: универсальный рендеринг, клиентский рендеринг, а также гибридный рендеринг и возможность рендерить приложение на CDN edge-серверах.
И браузер, и сервер могут выполнять JavaScript, превращая компоненты Vue.js в HTML. Этот шаг называется рендерингом. Nuxt поддерживает и универсальный, и клиентский рендеринг. У обоих подходов есть плюсы и минусы, о которых мы расскажем.
По умолчанию Nuxt использует универсальный рендеринг для лучшего UX, производительности и индексации в поисковиках, но режим можно изменить одной строкой конфигурации.
Универсальный рендеринг
Этот шаг похож на классический серверный рендеринг в PHP или Ruby. При запросе URL с включённым универсальным рендерингом Nuxt выполняет JavaScript (Vue.js) на сервере и отдаёт браузеру готовую HTML-страницу. Nuxt может также вернуть уже сгенерированную страницу из кэша. Пользователь сразу получает полное начальное содержимое приложения — в отличие от клиентского рендеринга.
После загрузки HTML браузер его обрабатывает, и Vue.js «подхватывает» документ. Тот же код, что выполнялся на сервере, снова выполняется в браузере при гидрации и «оживляет» страницу, подключая обработчики к уже отрисованному HTML. Это называется гидрацией. После гидрации страница становится интерактивной: переходы, динамика и т.д.
Универсальный рендеринг даёт быструю загрузку и сохраняет преимущества клиентского приложения. Кроме того, контент уже есть в HTML, поэтому поисковые роботы могут его индексировать без дополнительной нагрузки.
Что рендерится на сервере, а что — на клиенте?
В режиме универсального рендеринга логично спросить, какие части .vue-файла выполняются на сервере и/или клиенте.
<script setup lang="ts">
const counter = ref(0) // выполняется и на сервере, и на клиенте
const handleClick = () => {
counter.value++ // выполняется только на клиенте
}
</script>
<template>
<div>
<p>Счёт: {{ counter }}</p>
<button @click="handleClick">
Увеличить
</button>
</div>
</template>
При первом запросе ref счётчика инициализируется на сервере, так как он отображается в <p>. Код внутри handleClick на сервере не выполняется. При гидрации в браузере ref инициализируется заново, а handleClick привязывается к кнопке; поэтому тело handleClick всегда выполняется в браузере.
Мидлвары и страницы выполняются и на сервере, и на клиенте при гидрации. Плагины могут выполняться только на сервере, только на клиенте или на обоих. Компоненты можно принудительно выполнять только на клиенте. Композаблы и утилиты работают в зависимости от контекста использования.
Плюсы серверного рендеринга:
- Производительность: контент отображается сразу, так как статический HTML показывается быстрее, чем сгенерированный через JavaScript. При этом Nuxt сохраняет интерактивность после гидрации.
- SEO: универсальный рендеринг отдаёт полный HTML страницы, как классическое серверное приложение. Краулеры могут индексировать контент напрямую — это удобно для любого контента, который нужно быстро проиндексировать.
Минусы серверного рендеринга:
- Ограничения разработки: окружения сервера и браузера различаются по API, и писать код, одинаково работающий с обеих сторон, бывает непросто. Nuxt даёт рекомендации и переменные, чтобы понимать, где выполняется код.
- Затраты: нужен работающий сервер для рендеринга по запросу — это дополнительные расходы. Благодаря универсальному рендерингу и переходам на клиенте число обращений к серверу снижается. Дополнительно можно снизить затраты за счёт edge-side-rendering.
Универсальный рендеринг подходит почти для любых задач, особенно для блогов, маркетинговых сайтов, портфолио, интернет-магазинов и маркетплейсов.
Клиентский рендеринг
В классическом Vue.js-приложении по умолчанию рендеринг происходит в браузере (на клиенте). Vue.js создаёт HTML-элементы после того, как браузер загрузит и выполнит весь JavaScript с инструкциями по отрисовке интерфейса.
Плюсы клиентского рендеринга:
- Скорость разработки: при работе только на клиенте не нужно заботиться о совместимости с сервером — можно использовать только браузерные API, например объект
window. - Дешевле: сервер требует инфраструктуры. Клиентское приложение можно разместить на любом статическом хостинге с HTML, CSS и JS.
- Офлайн: код выполняется целиком в браузере, поэтому приложение может работать без интернета.
Минусы клиентского рендеринга:
- Производительность: пользователь ждёт загрузки, разбора и выполнения JavaScript. Время зависит от сети и устройства и может ухудшать опыт.
- SEO: индексация и обновление контента при чисто клиентском рендеринге занимает больше времени, чем при серверном HTML. Краулеры не ждут полной отрисовки интерфейса при первой попытке индексации, поэтому контент дольше появляется и обновляется в результатах поиска.
Клиентский рендеринг подходит для сильно интерактивных веб-приложений, которым не нужна индексация или которые пользователи открывают часто: SaaS, бэк-офис, онлайн-игры.
Включить только клиентский рендеринг в Nuxt можно в nuxt.config.ts:
export default defineNuxtConfig({
ssr: false,
})
ssr: false рекомендуется положить в ~/spa-loading-template.html HTML-файл с экраном загрузки, который будет показываться до гидрации приложения.Деплой статического клиентского приложения
При деплое на статический хостинг командами nuxt generate или nuxt build --prerender Nuxt по умолчанию рендерит каждую страницу в отдельный статический HTML-файл.
nuxt generate или nuxt build --prerender серверные эндпоинты недоступны — в выходной папке сервера не будет. Если нужна серверная логика, используйте nuxt build.При чисто клиентском рендеринге отдельные HTML-файлы для каждой страницы могут быть не нужны: достаточно одного index.html, плюс запасные 200.html и 404.html, которые хостинг будет отдавать на все запросы.
Чтобы так сделать, измените список пререндериваемых маршрутов в хуках в nuxt.config.ts:
export default defineNuxtConfig({
hooks: {
'prerender:routes' ({ routes }) {
routes.clear() // не генерировать маршруты (кроме дефолтных)
},
},
})
В результате будут созданы три файла:
index.html200.html404.html
200.html и 404.html могут понадобиться в зависимости от хостинга.
Отключение генерации клиентских fallback-файлов
При пререндере клиентского приложения Nuxt по умолчанию создаёт index.html, 200.html и 404.html. Чтобы запретить генерацию любого (или всех) из них, используйте хук Nitro prerender:generate.
// @errors: 2353 7006
export default defineNuxtConfig({
ssr: false,
nitro: {
hooks: {
'prerender:generate' (route) {
const routesToSkip = ['/index.html', '/200.html', '/404.html']
if (routesToSkip.includes(route.route)) {
route.skip = true
}
},
},
},
})
Гибридный рендеринг
Гибридный рендеринг позволяет задавать разные правила кэширования и рендеринга для маршрутов через Route Rules и управлять тем, как сервер отвечает на запрос по заданному URL.
Раньше все страницы и сервер Nuxt работали в одном режиме — универсальном или клиентском. На практике часть страниц удобнее генерировать при сборке, а другую — рендерить на клиенте. Например, контент-сайт с админкой: контентные страницы — статические и генерируются один раз, а админка требует авторизации и ведёт себя как динамическое приложение.
В Nuxt есть правила маршрутов и гибридный рендеринг. Через route rules можно задать правила для группы маршрутов, изменить режим рендеринга или стратегию кэширования.
Nuxt автоматически регистрирует соответствующие мидлвары и оборачивает маршруты обработчиками кэша через слой кэширования Nitro.
export default defineNuxtConfig({
routeRules: {
// Главная пререндерится при сборке
'/': { prerender: true },
// Страница товаров — по запросу, фоновое обновление, кэш до изменения ответа API
'/products': { swr: true },
// Страницы товаров — по запросу, кэш 1 час (3600 сек)
'/products/**': { swr: 3600 },
// Список постов — по запросу, кэш на CDN 1 час
'/blog': { isr: 3600 },
// Отдельный пост — по запросу один раз до следующего деплоя, кэш на CDN
'/blog/**': { isr: true },
// Админка только на клиенте
'/admin/**': { ssr: false },
// CORS для API
'/api/**': { cors: true },
// Редирект со старых URL
'/old-page': { redirect: '/new-page' },
},
})
Правила маршрутов (Route Rules)
Доступные свойства:
redirect: string— серверные редиректы.ssr: boolean— отключить серверный рендеринг HTML для части приложения (ssr: false— только в браузере).cors: boolean— добавить CORS-заголовки (cors: true); можно переопределить черезheaders.headers: object— задать заголовки для части сайта (например, ассетов).swr: number | boolean— заголовки кэширования и кэш ответа на сервере или за прокси с настраиваемым TTL. Пресет Nitronode-serverкэширует полный ответ. После истечения TTL отдаётся кэш, а страница регенерируется в фоне. Приtrueдобавляется заголовок stale-while-revalidate без MaxAge.isr: number | boolean— то же, чтоswr, но с кэшированием на CDN (поддерживается, в частности, Netlify и Vercel). Приtrueконтент хранится в CDN до следующего деплоя.prerender: boolean— пререндер маршрутов при сборке, результат попадает в билд как статика.noScripts: boolean— не подключать скрипты Nuxt и подсказки ресурсов для части сайта.appMiddleware: string | string[] | Record<string, boolean>— задать мидлвары, которые должны или не должны выполняться для путей страниц во Vue-части приложения (не Nitro-маршруты).
isr или swr также генерируются файлы _payload.json. При клиентской навигации загружаются эти кэшированные данные вместо повторного запроса. Динамические маршруты вроде pages/[...slug].vue настраивайте через glob: '/**': { isr: true }.По возможности правила маршрутов преобразуются в нативные правила платформы деплоя для оптимальной работы (сейчас поддерживаются Netlify и Vercel).
nuxt generate.Примеры:
Edge-Side Rendering
Edge-Side Rendering (ESR) — возможность рендерить Nuxt-приложение ближе к пользователю на edge-серверах CDN. Это уменьшает задержки и улучшает производительность.
При ESR рендеринг переносится на «край» сети — edge-серверы CDN. ESR скорее целевая среда деплоя, чем отдельный режим рендеринга.
При запросе страницы он обрабатывается ближайшим edge-сервером, а не исходным сервером. Этот сервер генерирует HTML и отдаёт его пользователю, сокращая задержку и ускоряя загрузку.
Edge-рендеринг реализован в Nitro — серверном движке Nuxt. Nitro поддерживает Node.js, Deno, Cloudflare Workers и другие платформы.
Платформы с поддержкой ESR:
- Cloudflare Pages — нулевая конфигурация при деплое через Git и команде
nuxt build - Vercel Cloud — команда
nuxt buildи переменная окруженияNITRO_PRESET=vercel-edge - Netlify Edge Functions — команда
nuxt buildи переменнаяNITRO_PRESET=netlify-edge
Гибридный рендеринг можно использовать вместе с Edge-Side Rendering через правила маршрутов.