Запропонувати правкуПокращити цю статтюДопрацюйте відповідь до «Які режими рендерингу в Nuxt (SSR, SSG, SPA, Hybrid)?». Ваші зміни проходять модерацію перед публікацією.Потрібне підтвердженняКонтентЩо ви змінюєте🇺🇸EN🇺🇦UAПереглядЗаголовок (UA)Коротка відповідь (UA)**Режими рендерингу Nuxt** визначають де і коли генерується HTML. SSR рендерить на сервері при кожному запиті (для SEO і динамічних даних). SSG збирає сторінки наперед через `nuxi generate` (для CDN і максимальної швидкості). SPA рендерить у браузері без сервера (`ssr: false`). Hybrid комбінує всі три підходи на рівні роутів через `routeRules`. ```typescript routeRules: { '/blog/**': { ssr: true }, '/admin/**': { ssr: false } } ``` **Ключове:** SSR і SSG одразу віддають готовий HTML. SPA надсилає JS-бандл і браузер збирає сторінку сам.Показується над повною відповіддю для швидкого нагадування.Відповідь (UA)Зображення**Режими рендерингу Nuxt** визначають де і коли генерується HTML: на сервері при кожному запиті (SSR), заздалегідь під час збірки (SSG), у браузері клієнта (SPA), або по-різному для кожного роута (Hybrid). ## Теорія ### TL;DR - SSR = кухня ресторану, яка готує страву під кожне замовлення. SSG = страви приготовані заздалегідь і чекають на видачу. SPA = продукти привезли додому і готуєш сам. Hybrid = для кожної страви свій підхід. - Головний поділ: SSR і SSG віддають готовий HTML з сервера. SPA надсилає JS-бандл, а браузер збирає сторінку самостійно. - SEO + свіжі дані? SSR. Статичний контент + CDN? SSG. Дашборд за логіном? SPA. Змішаний сайт? Hybrid через `routeRules`. - В основі всіх чотирьох режимів - Nitro, серверний рушій Nuxt. ### Швидкий приклад ```typescript // nuxt.config.ts - чотири режими в одному файлі export default defineNuxtConfig({ // SSR (за замовчуванням): сервер рендерить HTML при кожному запиті ssr: true, // SSG: запусти `npx nuxi generate` - отримаєш папку /dist зі статичними HTML-файлами // ssr: true + команда nuxi generate // SPA: браузер робить все сам, сервер віддає порожню оболонку // ssr: false // Hybrid (Nuxt 3): правила рендерингу по роутах routeRules: { '/blog/**': { ssr: true }, // SSR для SEO '/dashboard/**': { ssr: false } // SPA для інтерактивності } }) ``` Запусти `npx nuxi dev` з `ssr: true` і побачиш серверні логи при кожному переході на сторінку. Переключи на `ssr: false` і логи зникнуть. Браузер тепер сам з усім розбирається. ### Ключова різниця SSR і SSG обидва генерують справжній HTML, який одразу отримують і пошукові краулери, і користувачі. Відмінність у часі: SSR генерує HTML у момент запиту, SSG - один раз під час збірки. SPA взагалі не генерує HTML на сервері. Він надсилає JS-бандл, і браузер мусить завантажити, розібрати та виконати JavaScript перш ніж з'явиться будь-який контент. Ця затримка шкодить і SEO, і відчуттю швидкості. ### Коли що використовувати - **SEO + контент що часто оновлюється**: SSR. Новинні сайти, сторінки товарів e-commerce, все де дані міняються щогодини. - **Статичний контент, швидкість CDN**: SSG. Документація, маркетингові сторінки, лендінги. Сам nuxt.com побудований через `nuxi generate`. - **Інтерактивний додаток без SEO**: SPA. Адмін-панелі, дашборди, все що за авторизацією. - **Змішаний сайт (блог + адмін)**: Hybrid через `routeRules`. Роути блогу отримують SSR, адмін - SPA. - **Персоналізовані дані**: SSR або Hybrid, де `useAsyncData` або `useFetch` виконується на сервері. ### Таблиця порівняння | Параметр | SSR | SSG | SPA | Hybrid | |---|---|---|---|---| | **Доставка HTML** | Сервер при запиті | Статичні файли зі збірки | Порожня оболонка + JS | По-різному для кожного роута | | **SEO** | Відмінне | Відмінне | Погане (залежить від JS) | Залежить від роута | | **TTFB** | Середній (обчислення сервера) | Найшвидший (CDN edge) | Повільний (завантаження + виконання JS) | Оптимізовано для кожного роута | | **Динамічні дані** | Повна підтримка (`useAsyncData`) | Тільки під час збірки | Запити з клієнта | Змішано | | **Час збірки** | Швидко | Зростає з кількістю сторінок | Найшвидше | Як SSR + статичні роути | | **Витрати на сервер** | Високі (кожен запит) | Нуль (CDN) | Нуль після деплою | Низькі (тільки SSR-роути) | | **Підходить для** | E-commerce, блоги | Документація, лендінги | Адмін-панелі | Більшість реальних проектів | ### Як Nitro це обробляє Nitro, серверний рушій Nuxt, компілює Vue-компоненти в серверні рендерери для SSR і SSG. У режимі SSR Nitro виконує `useAsyncData` і `useFetch` в Node.js при кожному запиті, серіалізує результат в HTML і додає JSON-пейлоад у теги `<script>` для клієнтської гідрації. SSG робить те саме, але один раз при збірці і записує `.html`-файли. Режим SPA повністю оминає рендерер Nitro. Vite збирає бандл для браузера. Hybrid-режим аналізує `routeRules` і маршрутизує SSR-шляхи до обробників Nitro, а SPA-шляхи до клієнтської точки входу. Повна послідовність для Hybrid-запиту до `/blog/post`: запит потрапляє до Nitro, збігається з правилом `ssr: true`, Vue рендериться у рядок HTML через `@vue/server-renderer`, виконується `useAsyncData` в Node, JSON-пейлоад додається в `<script>`, відповідь стримується клієнту. ### Типові помилки **1. `ssr: false` на сайті що потребує SEO.** ```typescript // Неправильно: краулери отримують порожній div export default defineNuxtConfig({ ssr: false }) // curl http://localhost:3000 → <div id="__nuxt"></div> // Правильно: тримай SSR і перевіряй через curl export default defineNuxtConfig({ ssr: true }) // curl http://localhost:3000 → <article>Повний текст поста</article> ``` **2. `useFetch` у SSG для зовнішніх API, яких нема під час збірки.** ```typescript // Неправильно: збірка впаде, бо API недоступне в момент nuxi generate const { data } = await useFetch('/api/live-prices') // Правильно: виконуй тільки на клієнті const { data } = await useFetch('/api/live-prices', { server: false }) ``` **3. Клієнт-only компоненти без `<ClientOnly>` на SSR-роутах.** Компонент, який звертається до `window` або `document`, зламає серверний рендеринг. Огорни його: ```vue <ClientOnly> <HeavyChartComponent /> </ClientOnly> ``` **4. `nuxi build` замість `nuxi generate` для SSG-деплою.** `nuxi build` створює SSR-сервер на Node.js. `nuxi generate` виводить статичні HTML-файли для CDN. Неправильна команда - неправильний тип виводу і зламаний деплой. **5. Очікування що SSG обробить невідомі динамічні параметри.** Якщо під час збірки згенеровано `/users/1`, `/users/2`, `/users/3`, запит до `/users/99` поверне 404. SSG фіксує тільки ті сторінки, які знає при збірці. Для всіх можливих ID правильний вибір - SSR. ### Де зустрічається в реальних проектах - **nuxt.com** використовує SSG через `nuxi generate`, задеплоєний на CDN. - **Vercel** автоматично розпізнає SSG-роути з `routeRules` у Hybrid-деплоях. - **E-commerce сайти** застосовують SSR для кошика і checkout, SSG для каталогу товарів. - **Nuxt + Contentful** використовують SSR-блоги з `useAsyncData`. - **Адмін-панелі** отримують `ssr: false` на роутах `/admin/**`. ### Питання на співбесіді **Q:** Чим Hybrid у Nuxt 3 відрізняється від universal mode у Nuxt 2? **A:** Nuxt 2 мав єдину глобальну SSR + клієнтська гідрація модель. У Nuxt 3 через `routeRules` можна вибирати режим для кожного роута окремо: SSR для `/blog/**` і SPA-поведінку для `/admin/**` в одному додатку без жодного глобального перемикача. **Q:** Що відбувається з `useState` у SSG? **A:** При збірці стан ініціалізується на сервері звично. Після гідрації на клієнті `useState` зберігається в пам'яті браузера. Але оскільки сервера при рантаймі нема, стан не переживає перезавантаження сторінки так само, як в SSR. **Q:** Як симулювати ISR у Nuxt? **A:** Нативного ISR, як у Next.js, у Nuxt нема. Найближче рішення - `routeRules` з `swr: 3600` (stale-while-revalidate): сторінка подається з кешу миттєво, а в фоні відбувається ревалідація. Для повноцінної схеми з вебхук-перезбірками потрібно комбінувати `prerender: true` з CI-тригером. **Q:** Як дебажити повільний SSR time-to-interactive? **A:** Профілюй Nitro через dev tools, використовуй `useLazyFetch` для некритичних даних щоб перший HTML прийшов швидше, і огортай важкі сторонні компоненти у `<ClientOnly>` щоб не блокувати серверний рендеринг. **Q:** Що в Hybrid-режимі визначає чи використовує роут SSR або SPA? Відстеж повну послідовність. **A:** Правила `routeRules` у `nuxt.config.ts`. Запит потрапляє до Nitro, збігається з патерном шляху, і якщо правило `ssr: false` - Nitro повертає клієнтську HTML-оболонку. Якщо `ssr: true` - Vue рендериться через `@vue/server-renderer`, `useAsyncData` виконується в Node, JSON-пейлоад вбудовується у `<script>`, повна HTML-відповідь стримується клієнту. ## Приклади ### SSR-сторінка блогу з серверним завантаженням даних ```vue <!-- pages/blog/[slug].vue --> <template> <article> <h1>{{ post.title }}</h1> <div v-html="post.body" /> </article> </template> <script setup> const route = useRoute() // useAsyncData виконується на сервері - краулери бачать повний контент const { data: post } = await useAsyncData('post', () => $fetch(`/api/posts/${route.params.slug}`) ) </script> ``` Сервер виконує `$fetch` до `/api/posts/[slug]` ще до відправки HTML клієнту. Якщо переглянути код сторінки, заголовок і тіло статті вже в розмітці - JavaScript їх не вставляє пізніше. ### Hybrid-додаток: блог і адмін-панель ```typescript // nuxt.config.ts export default defineNuxtConfig({ routeRules: { '/blog/**': { ssr: true }, // Повний SSR: SEO + свіжі дані '/dashboard/**': { ssr: false }, // SPA: краулери не потрібні, багата інтерактивність '/': { prerender: true } // SSG головна: максимально швидкий TTFB } }) ``` ```vue <!-- pages/dashboard/analytics.vue - виконується тільки на клієнті --> <script setup> const { data: stats } = await useFetch('/api/analytics', { server: false }) </script> ``` Три різних поведінки в одному Nuxt-додатку. Головна сторінка - статичний файл на CDN. Пости блогу - SSR з Node-сервера. Дашборд - SPA-оболонка, яка завантажує свої дані після монтування. ### E-commerce з ISR-подібним кешуванням ```typescript // nuxt.config.ts - реальне налаштування e-commerce export default defineNuxtConfig({ routeRules: { '/': { prerender: true }, // Статична головна сторінка '/products': { swr: 600 }, // Каталог: кеш 10 хв, ревалідація у фоні '/products/**': { swr: 3600 }, // Сторінки товарів: кеш 1 година '/cart': { ssr: false }, // SPA кошик: персональний, SEO не потрібен '/checkout': { ssr: true }, // SSR checkout: безпека + персоналізація '/admin/**': { ssr: false } // SPA адмін-панель } }) ``` `swr` (stale-while-revalidate) відразу віддає закешований контент і запускає ревалідацію у фоні після закінчення кеш-вікна. Сторінки товарів завантажуються швидко з кешу і при цьому залишаються достатньо актуальними. Це максимально близько до ISR у Next.js без зовнішніх тригерів перезбірки.Для рев’юераПримітка для модератора (необов’язково)Бачить лише модератор. Прискорює рев’ю.