Don't miss Vue.js Amsterdam in March 2025! Save 10% with code NUXT.

Режимы рендеринга

Узнайте о разных режимах рендеринга, доступных в Nuxt.

Nuxt поддерживает разные режимы рендеринга: универсальный рендеринг, рендеринг на клиенте, а также предоставляет гибридный рендеринг и возможность рендерить ваше приложение на пограничных CDN-серверах.

И браузер, и сервер могут интерпретировать код JavaScript для преобразования компонентов Vue.js в HTML-элементы. Этот шаг называется рендеринг. Nuxt поддерживает как универсальный, так и клиентский рендеринги. У этих двух подходов есть преимущества и недостатки, которые мы рассмотрим.

По умолчанию Nuxt использует универсальный рендеринг, чтобы обеспечить лучший пользовательский опыт, производительность и оптимизировать индексацию поисковыми системами, но вы можете переключать режимы рендеринга с помощью одной строки конфигурации.

Универсальный Рендеринг

This step is similar to traditional server-side rendering performed by PHP or Ruby applications. When the browser requests a URL with universal rendering enabled, Nuxt runs the JavaScript (Vue.js) code in a server environment and returns a fully rendered HTML page to the browser. Nuxt may also return a fully rendered HTML page from a cache if the page was generated in advance. Users immediately get the entirety of the initial content of the application, contrary to client-side rendering.

Once the HTML document has been downloaded, the browser interprets this and Vue.js takes control of the document. The same JavaScript code that once ran on the server runs on the client (browser) again in the background now enabling interactivity (hence Universal rendering) by binding its listeners to the HTML. This is called Hydration. When hydration is complete, the page can enjoy benefits such as dynamic interfaces and page transitions.

Универсальный рендеринг позволяет Nuxt-приложению обеспечить быструю загрузку страницы, сохраняя при этом преимущества рендеринга на клиенте. Более того, поскольку контент уже присутствует в HTML-документе, поисковые роботы могут индексировать его без дополнительных затрат.

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

What's server-rendered and what's client-rendered?

It is normal to ask which parts of a Vue file runs on the server and/or the client in universal rendering mode.

app.vue
<script setup lang="ts">
const counter = ref(0); // executes in server and client environments

const handleClick = () => {
  counter.value++; // executes only in a client environment
};
</script>

<template>
  <div>
    <p>Count: {{ counter }}</p>
    <button @click="handleClick">Increment</button>
  </div>
</template>

On the initial request, the counter ref is initialized in the server since it is rendered inside the <p> tag. The contents of handleClick is never executed here. During hydration in the browser, the counter ref is re-initialized. The handleClick finally binds itself to the button; Therefore it is reasonable to deduce that the body of handleClick will always run in a browser environment.

Middlewares and pages run in the server and on the client during hydration. Plugins can be rendered on the server or client or both. Components can be forced to run on the client only as well. Composables and utilities are rendered based on the context of their usage.

Benefits of server-side rendering:

  • Performance: Users can get immediate access to the page's content because browsers can display static content much faster than JavaScript-generated content. At the same time, Nuxt preserves the interactivity of a web application during the hydration process.
  • Search Engine Optimization: Universal rendering delivers the entire HTML content of the page to the browser as a classic server application. Web crawlers can directly index the page's content, which makes Universal rendering a great choice for any content that you want to index quickly.

Недостатки рендеринга на сервере:

  • Ограничения разработки: Среды сервера и браузера не предоставляют одни и те же API, и может быть сложно написать код, который мог бы беспрепятственно выполняться на обеих сторонах. К счастью, Nuxt предоставляет рекомендации и специальные переменные, которые помогут вам определить, где выполняется фрагмент кода.
  • Стоимость: Чтобы отображать страницы «на лету», должен быть запущен сервер. Это добавляет ежемесячные расходы, как и у любого традиционного сервера. Однако количество вызовов сервера значительно сокращается благодаря универсальному рендерингу, когда браузер берет на себя навигацию на стороне клиента. Снижение затрат возможно за счет использования пограничного рендеринга.

Универсальный рендеринг очень гибок и может подойти практически для любого варианта использования и особенно подходит для любых контентно-ориентированных веб-сайтов: блоги, маркетинговые веб-сайты, портфолио, сайты электронной коммерции и торговые площадки.

Дополнительные примеры написания кода Vue без несоответствия гидратации смотрите в документации Vue.
При импорте библиотеки, которая использует API браузера и имеет побочные эффекты, убедитесь, что импортирующий ее компонент вызывается только на стороне клиента. Бандлеры не обрабатывают импорт модулей, содержащих побочные эффекты.

Рендеринг на клиенте

Из коробки традиционное Vue.js приложение рендерится в браузере (или на клиенте). После того, как браузер загрузит и спарсит весь JavaScript код, содержащий инструкции для создания текущего интерфейса, Vue.js генерирует HTML-элементы.

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

Преимущества рендеринга на клиенте:

  • Скорость разработки: При работе полностью на клиенте нам не нужно беспокоиться о совместимости кода с сервером, например, при использовании API, доступного только для браузера, такого как объект window.
  • Дешевле: Запуск сервера увеличивает стоимость инфраструктуры, поскольку вам потребуется работать на платформе, поддерживающей JavaScript. Мы можем размещать клиентские приложения на любом статическом сервере с файлами HTML, CSS и JavaScript.
  • Оффлайн: Поскольку код полностью выполняется в браузере, он может продолжать работать, даже если интернет недоступен.

Недостатки рендеринга на клиенте:

  • Производительность: Пользователю приходится ждать, пока браузер загрузит, проанализирует и запустит файлы JavaScript. В зависимости от сети, в которой выполняется загрузка, и устройства пользователя, на котором выполняется анализ и выполнение, это может занять некоторое время и повлиять на пользовательский опыт.
  • Поисковая оптимизация: Индексирование и обновление контента, доставленного посредством рендеринга на клиенте, занимает больше времени, чем при обработке HTML-документа, отрисованного на сервере. Это связано с недостатком производительности, который мы обсуждали, поскольку поисковые роботы не будут ждать полной визуализации интерфейса при первой попытке индексировать страницу. Вашему контенту потребуется больше времени, чтобы отобразиться и обновиться на страницах результатов поиска с рендерингом полностью на клиенте.

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

Вы можете включить рендеринг только на клиенте с помощью Nuxt в вашем nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  ssr: false
})
Если вы успользуете ssr: false, вы должны поместить в ~/app/spa-loading-template.html HTML-файл с некоторым HTML-кодом, который вы хотите использовать для рендеринга экрана загрузки, который будет отображаться до тех пор, пока ваше приложение не будет гидратировано.
Узнать больше SPA Loading Template.
Посмотрите видео Александра Лихтера про Создание чистого SPA с Nuxt!?.

Развертывание статичного приложения, отрисованного на стороне клиента

Если вы размещаете приложение на статичном хостинге с помощью команд nuxi generate или nuxi build --prerender, то по умолчанию Nuxt будет рендерить каждую страницу как отдельный статичный HTML-файл.

Если вы используете рендеринг полностью на клиенте, тогда это может быть ненужно. Возможно, вам понадобится только один index.html файл, плюс запасные 200.html и 404.html, которые вы можете указать своему статическому веб-хосту для обслуживания всех запросов.

Чтобы добиться этого, мы можем поменять способ рендеринга маршрутов. Просто добавьте это к вашим хукам в nuxt.config.ts:

nuxt.config.ts
export default 
defineNuxtConfig
({
hooks
: {
'prerender:routes' ({
routes
}) {
routes
.
clear
() // Не создает никаких маршрутов (кроме значений по умолчанию)
} }, })

Это создаст три файла:

  • index.html
  • 200.html
  • 404.html

200.html и 404.html могут быть полезны для используемого вами хостинг-провайдера.

Гибридный рендеринг

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

Раньше каждый маршрут/страница Nuxt-приложения и сервер должны были использовать одинаковый режим рендеринга, универсальный или клиентский. В различных случаях некоторые страницы должны быть созданы во время сборки, в то время как другие должны быть отрисованы на клиенте. Например, подумайте о контентных сайтах с админ-частью. Каждая страница с контеном должна быть в первую очередь статической и генерироваться один раз, но админ-часть требует регистрации и ведет себя скорее как динамическое приложение.

Nuxt включает в себя правила маршрутизации и поддержку гибридного рендеринга. Используя правила маршрутизации, вы можете определить правила для группы маршрутов nuxt, меняя режим рендеринга или назначая стратегию кэширования, основанную на маршруте!

Nuxt-сервер будет автоматически регистрировать соответствующие middleware и оборачивать маршруты обработчиками кэша, используя слой кеширования Nitro.

nuxt.config.ts
export default 
defineNuxtConfig
({
routeRules
: {
// Домашняя страница предварительно отрисовывается во время сборки '/': {
prerender
: true },
// Страница продуктов создается по требованию, повторно проверяется в фоновом режиме, кэшируется до изменения ответа API '/products': {
swr
: true },
// Страницы продукта создается по требованию, повторно проверяется в фоновом режиме, кэшируется на один час (3600 секунд) '/products/**': {
swr
: 3600 },
// Страница сообщений в блоге создается по требованию, повторно проверяется в фоновом режиме, кэшируется на CDN на один час (3600 секунд) '/blog': {
isr
: 3600 },
// Страница сообщения в блоге создается по требованию до следующего развертывания, кэшируется на CDN '/blog/**': {
isr
: true },
// Панель управления администратора рендерится только на клиенте '/admin/**': {
ssr
: false },
// Добавляет CORS-заголовки на маршрутах API '/api/**': {
cors
: true },
// Перенаправляет старые URL-адреса '/old-page': {
redirect
: '/new-page' }
} })

Правила маршрутизации

Вы можете использовать следующие свойства:

  • redirect: string - Определяет перенаправления на сервере.
  • ssr: boolean - Отключaет серверный рендеринг HTML для разделов вашего приложения, чтобы они рендерились только в браузере.ssr: false.
  • cors: boolean - Автоматически добавляет cors-заголовки с cors: true - вы можете настроить вывод, переопределив с помощью headers.
  • headers: object - Добавляет определенные заголовки в разделы вашего сайта, например, в ассеты.
  • swr: number | boolean - Добавляет заголовки кэша к ответу сервера и кэширует его на сервере или обратном прокси-сервере для настраиваемого TTL (time to live - времени жизни). Настройка Nitro node-server способна кэшировать полный ответ. По истечении срока жизни (TTL) будет отправлен кэшированный ответ, а страница будет перегенерирована в фоновом режиме. Если импользуется true, будет добавлен заголовок stale-while-revalidate без MaxAge.
  • isr: number | boolean - Поведение схоже с swr, за исключением того, что мы можем добавить ответ в кеш CDN на платформах, которые это поддерживают (в настоящее время Netlify или Vercel). Если используется true, контент сохраняется до следующего развертывания внутри CDN.
  • prerender: boolean - Предварительно отрисовывает маршруты во время сборки и включает их в сборку как статические ресурсы.
  • experimentalNoScripts: boolean - Отключает рендеринг скриптов Nuxt и подсказок ресурсов JS для разделов вашего сайта.
  • appMiddleware: string | string[] | Record<string, boolean> - Позволяет вам определить middleware, которое должно или не должно запускаться для путей к страницам в части Vue вашего приложения (то есть не для ваших маршрутов Nitro).

По возможности правила маршрутизации будут автоматически применяться к собственным правилам платформы развертывания для достижения оптимальной производительности (в настоящее время поддерживаются Netlify и Vercel).

Обратите внимание, что гибридный рендеринг недоступен при использовании nuxt generate.

Примеры:

Nuxt Vercel ISR

Пример Nuxt-приложения с гибридным рендерингом, развернутом на Vercel.

Пограничный рендеринг

Пограничный рендеринг (Edge-Side Rendering - ESR) — это мощная функция, представленная в Nuxt, которая позволяет отображать ваше приложение Nuxt ближе к вашим пользователям через пограничные серверы сети доставки контента (CDN). Используя ESR, вы можете обеспечить повышенную производительность и сокращение задержек, тем самым обеспечивая улучшенный пользовательский опыт.

При использовании ESR процесс рендеринга переносится на «край» сети — пограничные серверы CDN. Обратите внимание, что ESR — это скорее цель развертывания, чем реальный режим рендеринга.

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

Пограничный рендеринг возможен, благодаря Nitro - серверному движку - который обеспечивает работу Nuxt 3. Он предлагает кроссплатформенную поддержку Node.js, Deno, Cloudflare Workers и других.

Текущие платформы, на которых вы можете использовать ESR:

  • Cloudflare Pages с нулевой конфигурацией с использованием git-интеграции и команды nuxt build
  • Vercel Edge Functions с использованием команды nuxt build и переменной окружения NITRO_PRESET=vercel-edge
  • Netlify Edge Functions с использованием команды nuxt build и переменной окружения NITRO_PRESET=netlify-edge

Обратите внимание, что гибридный рендеринг можно использовать при использовании пограничного рендеринга с правилами маршрутизации.

Вы можете изучить примеры с открытым исходным кодом, развернутые на некоторых платформах, упомянутых выше:

Nuxt Todos Edge

Приложение со списком дел с аутентификацией пользователей, SSR и SQLite.

Atinotes

Редактируемый сайт с универсальным рендерингом на Cloudflare KV.