# Nuxt 3: SSR і статична генерація, повний посібник
> Опанувати SSR і статичну генерацію з Nuxt 3. Від useFetch до route rules: як оптимізувати продуктивність застосунків Vue.js.
- Published: 2026-02-11
- Updated: 2026-04-28
- Author: SharpSkill
- Tags: nuxt 3, vue.js, ssr, статична генерація, веб-продуктивність
- Reading time: 12 min
---
Nuxt 3 змінює спосіб створення застосунків Vue.js, пропонуючи кілька режимів рендерингу, що пасують до різних сценаріїв. Від Server-Side Rendering (SSR) до статичної генерації та гібридного рендерингу — фреймворк надає виняткову гнучкість для оптимізації продуктивності та SEO.
> **Передумови**
>
> Цей посібник передбачає базові знання Vue 3 та Composition API. Знайомство з концепціями серверного рендерингу буде корисним, але не обов'язковим, оскільки основи пояснюються по ходу матеріалу.
## Розуміння режимів рендерингу Nuxt 3
Перед тим як занурюватися в код, важливо зрозуміти відмінності між доступними режимами рендерингу. Кожен режим відповідає на конкретні потреби щодо продуктивності, SEO та користувацького досвіду.
SSR (Server-Side Rendering) генерує HTML на сервері для кожного запиту. Статична генерація (SSG) попередньо генерує всі сторінки на етапі збірки. Гібридний режим дозволяє поєднувати ці підходи посторінково.
```typescript
// nuxt.config.ts
// Конфігурація різних режимів рендерингу
export default defineNuxtConfig({
// SSR увімкнено за замовчуванням (рекомендовано для SEO)
ssr: true,
// Статична генерація: попередньо рендерить усі сторінки
// Використовуйте 'npm run generate' для збірки
// target: 'static', // Синтаксис Nuxt 2
// Гібридний режим: налаштовується для кожного маршруту
routeRules: {
// Головна сторінка: попередньо рендериться та кешується
'/': { prerender: true },
// Блог: статична генерація
'/blog/**': { prerender: true },
// Dashboard: рендеринг лише на клієнті
'/dashboard/**': { ssr: false },
// API: без попереднього рендерингу
'/api/**': { prerender: false }
}
})
```
Ця конфігурація демонструє силу гібридного режиму: кожна частина застосунку використовує найбільш відповідний для своїх потреб режим рендерингу.
## Отримання даних із useFetch і useAsyncData
Nuxt 3 надає два основні composables для ізоморфного отримання даних. Вони працюють як на сервері, так і на клієнті, з автоматичним керуванням гідратацією.
`useFetch` — це обгортка над `useAsyncData`, що спрощує HTTP-виклики. `useAsyncData` дає більше контролю в розширених сценаріях.
```vue
Завантаження статті...
{{ article.title }}
```
Для випадків, що потребують більшого контролю, `useAsyncData` дозволяє виконати будь-яку асинхронну функцію.
```vue
```
Ці composables запобігають подвійному отриманню даних: дані, отримані на сервері, серіалізуються в HTML-payload і повторно використовуються під час гідратації на клієнті.
## Налаштування SSR за допомогою server hooks
SSR у Nuxt 3 можна налаштувати через server hooks. Ці хуки дозволяють втручатися на різних етапах циклу рендерингу, щоб змінити стандартну поведінку.
```typescript
// server/plugins/render-hooks.ts
// Серверний плагін для кастомізації SSR-рендерингу
export default defineNitroPlugin((nitroApp) => {
// Хук, що виконується перед рендерингом кожної сторінки
nitroApp.hooks.hook('render:html', (html, { event }) => {
// Інжекція скриптів або метаданих
html.head.push(`
`)
})
// Хук для керування кешем рендерингу
nitroApp.hooks.hook('render:response', (response, { event }) => {
// Додавання кастомних заголовків кешу
const path = event.path
if (path.startsWith('/blog/')) {
// Тривалий кеш для статей блогу
response.headers['Cache-Control'] = 'public, max-age=3600, s-maxage=86400'
} else if (path.startsWith('/api/')) {
// Без кешу для API
response.headers['Cache-Control'] = 'no-store'
}
})
})
```
> **Продуктивність SSR**
>
> Хук `render:response` ідеально підходить для впровадження стратегій HTTP-кешу. Поєднання SSR із CDN, який поважає заголовки Cache-Control, дозволяє віддавати попередньо відрендерені сторінки, зберігаючи можливість їх інвалідації.
## Статична генерація з nuxt generate
Статична генерація заздалегідь будує всі сторінки на етапі збірки. Цей підхід ідеальний для сайтів зі стабільним контентом — блогів, документації або маркетингових сайтів.
Для динамічних маршрутів Nuxt має знати всі URL, які треба згенерувати. Хук `prerender:routes` дозволяє визначати ці маршрути програмно.
```typescript
// nuxt.config.ts
// Повна конфігурація для статичної генерації
export default defineNuxtConfig({
// Увімкнути статичну генерацію
nitro: {
prerender: {
// Увімкнути автоматичне сканування посилань
crawlLinks: true,
// Маршрути, які завжди потрібно включати
routes: ['/', '/about', '/contact'],
// Ігнорувати певні маршрути
ignore: ['/admin', '/api']
}
},
hooks: {
// Хук для генерації динамічних маршрутів
async 'prerender:routes'(ctx) {
// Отримання статей з API або БД
const articles = await fetch('https://api.example.com/articles')
.then(res => res.json())
// Додавання маршрутів статей
for (const article of articles) {
ctx.routes.add(`/blog/${article.slug}`)
}
// Отримання категорій
const categories = await fetch('https://api.example.com/categories')
.then(res => res.json())
for (const category of categories) {
ctx.routes.add(`/category/${category.slug}`)
}
}
}
})
```
Для проєктів із багатьма сторінками автоматичний crawler може бути недостатнім. Ось більш надійний підхід з окремим конфігураційним файлом.
```typescript
// server/utils/generate-routes.ts
// Утиліта для генерації списку динамічних маршрутів
import { prisma } from './prisma'
export async function getAllStaticRoutes(): Promise {
const routes: string[] = []
// Статті блогу
const articles = await prisma.article.findMany({
where: { published: true },
select: { slug: true, category: { select: { slug: true } } }
})
for (const article of articles) {
routes.push(`/blog/${article.category.slug}/${article.slug}`)
}
// Сторінки продуктів
const products = await prisma.product.findMany({
where: { active: true },
select: { slug: true }
})
for (const product of products) {
routes.push(`/products/${product.slug}`)
}
// Сторінки тегів
const tags = await prisma.tag.findMany({
select: { slug: true }
})
for (const tag of tags) {
routes.push(`/tags/${tag.slug}`)
}
return routes
}
```
## Гібридний рендеринг із routeRules
Гібридний рендеринг — флагманська функція Nuxt 3. Він дозволяє визначати різні правила рендерингу для кожного маршруту, поєднуючи переваги SSR та SSG.
```typescript
// nuxt.config.ts
// Розширена конфігурація гібридного рендерингу
export default defineNuxtConfig({
routeRules: {
// Маркетингові сторінки: попередньо відрендерені та довго кешовані
'/': { prerender: true },
'/pricing': { prerender: true },
'/features/**': { prerender: true },
// Блог: ISR (Incremental Static Regeneration)
// Ревалідація щогодини
'/blog/**': {
isr: 3600,
prerender: true
},
// Документація: CDN-кеш з ревалідацією
'/docs/**': {
swr: 86400, // Stale-while-revalidate
prerender: true
},
// E-commerce: SSR з коротким кешем
'/products/**': {
ssr: true,
cache: {
maxAge: 60,
staleMaxAge: 300
}
},
// Кошик і checkout: лише на клієнті
'/cart': { ssr: false },
'/checkout/**': { ssr: false },
// Dashboard: режим SPA
'/dashboard/**': {
ssr: false,
// Вимкнути попередній рендеринг
prerender: false
},
// API маршрути: без кешу за замовчуванням
'/api/**': {
cors: true,
headers: {
'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE'
}
}
}
})
```
Ця конфігурація ілюструє типову архітектуру сучасного застосунку: публічні сторінки оптимізуються для SEO за допомогою SSG, тоді як інтерактивні розділи використовують клієнтський рендеринг.
## Оптимізація продуктивності з кешем даних
Окрім кешу сторінок, Nuxt 3 дозволяє кешувати отримані дані. Ця стратегія знижує навантаження на API та покращує час відповіді.
```typescript
// server/api/articles/[slug].get.ts
// API-ендпоінт із кешем даних
import { getArticleBySlug } from '~/server/utils/articles'
export default defineCachedEventHandler(
async (event) => {
const slug = getRouterParam(event, 'slug')
if (!slug) {
throw createError({
statusCode: 400,
message: 'Відсутній slug'
})
}
const article = await getArticleBySlug(slug)
if (!article) {
throw createError({
statusCode: 404,
message: 'Статтю не знайдено'
})
}
return article
},
{
// Ключ кешу на основі slug
getKey: (event) => `article-${getRouterParam(event, 'slug')}`,
// Тривалість кешу: 1 година
maxAge: 3600,
// Stale-while-revalidate: віддавати застарілий кеш під час оновлення
staleMaxAge: 7200,
// Інвалідація на основі тегів
tags: ['articles']
}
)
```
Для інвалідації кешу при зміні контенту Nuxt надає систему тегів.
```typescript
// server/api/articles/[slug].put.ts
// Оновлення статті з інвалідацією кешу
import { updateArticle } from '~/server/utils/articles'
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, 'slug')
const body = await readBody(event)
// Оновлення статті
const article = await updateArticle(slug, body)
// Інвалідація кешу для цієї статті
await useStorage('cache').removeItem(`nitro:handlers:article-${slug}`)
// Або інвалідація на основі тегів (всі статті)
// await useStorage('cache').clear('articles')
return article
})
```
> **Розподілений кеш**
>
> У продакшені з кількома інстансами кеш у пам'яті недостатній. Рекомендується налаштувати Redis або іншу розподілену систему через конфігурацію Nitro, щоб забезпечити узгодженість між інстансами.
## Керування SEO та метаданими
SSR дозволяє оптимізувати SEO, генеруючи метадані на сервері. Nuxt 3 пропонує кілька підходів до динамічного керування meta tag'ами.
```vue
```
Для статичних сторінок метадані можна визначати безпосередньо в компоненті.
```vue
```
## Розгортання та виробничі міркування
Вибір способу розгортання залежить від обраного режиму рендерингу. Ось основні варіанти та їхні конфігурації.
```typescript
// nuxt.config.ts
// Конфігурація для різних середовищ розгортання
export default defineNuxtConfig({
nitro: {
// Preset відповідно до цільової платформи
// preset: 'vercel', // Vercel
// preset: 'netlify', // Netlify
// preset: 'cloudflare-pages', // Cloudflare
// preset: 'node-server', // Класичний Node.js
// Конфігурація для Node.js у продакшені
preset: 'node-server',
// Стиснення відповідей
compressPublicAssets: true,
// Конфігурація сховища кешу
storage: {
cache: {
driver: 'redis',
url: process.env.REDIS_URL
}
}
},
// Змінні середовища під час виконання
runtimeConfig: {
// Секрети (не доступні клієнту)
apiSecret: process.env.API_SECRET,
// Публічна конфігурація
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api'
}
}
})
```
Для статичного розгортання команда `npm run generate` створює папку `.output/public`, готову до розміщення на будь-якому хостингу статичних файлів.
```bash
# Статична генерація
npm run generate
# Вміст .output/public можна розгорнути на:
# - Vercel (автоматичне визначення)
# - Netlify (автоматична конфігурація)
# - GitHub Pages
# - S3 + CloudFront
# - Будь-якому CDN або сервері статичних файлів
```
## Висновок
Nuxt 3 пропонує виняткову гнучкість для рендерингу застосунків Vue.js. Вибір між SSR, SSG та гібридним рендерингом залежить від конкретних потреб кожного проєкту.
**Ключові висновки:**
✅ **SSR**: ідеально для динамічного контенту, що потребує гарного SEO (e-commerce, новинні сайти)
✅ **SSG**: чудово для стабільного контенту (блоги, документація, маркетингові сайти)
✅ **Гібридний**: найкращий підхід для складних застосунків з різноманітними потребами
✅ **useFetch/useAsyncData**: автоматична гідратація та керування кешем
✅ **routeRules**: точне налаштування поведінки кожного маршруту
✅ **Кешування**: множина стратегій для оптимізації продуктивності в продакшені
Поєднання гібридного рендерингу з продуманою стратегією кешування дозволяє створювати продуктивні застосунки, оптимізовані для SEO, зберігаючи інтерактивність Single Page Applications.
---
Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack.
HTML version of this page: https://sharpskill.dev/uk/blog/vue-nuxt/nuxt-3-ssr-static-generation