Nuxt 4 в SPA режиме
Контекст
Платформа может включать несколько фронтенд-приложений с разными требованиями к рендерингу. Нужен единый фреймворк и система модулей.
Решение
Использовать Nuxt 4 с гибридным подходом к рендерингу в зависимости от типа приложения.
Режимы рендеринга
SPA (Single Page Application)
Когда использовать: Приложения за авторизацией, где SEO не важен.
Примеры приложений:
- Admin-панели — управление контентом, пользователями, настройками
- CRM-системы — работа с клиентами, сделками, задачами
- Dashboard-приложения — аналитика, отчёты, мониторинг
- Внутренние корпоративные порталы — HR-системы, базы знаний
- Личные кабинеты — настройки профиля, история заказов
SSR (Server-Side Rendering)
Когда использовать: Динамический контент, требующий SEO и персонализации.
Примеры приложений:
- E-commerce каталоги — товары с динамическими ценами и остатками
- Новостные порталы — статьи с частыми обновлениями
- Социальные сети — посты, профили с динамическим контентом
- Маркетплейсы — объявления, отзывы, рейтинги
- Форумы и Q&A платформы — обсуждения, ответы, комментарии
SSG (Static Site Generation)
Когда использовать: Статический контент, редко меняющийся, максимальная скорость.
Примеры приложений:
- Лендинги и промо-страницы — продуктовые страницы, акции
- Блоги и статьи — технические блоги, гайды, туториалы
- Документация — API-документация, справочники
- Маркетинговые сайты — корпоративные сайты, портфолио
- Страницы тарифов и FAQ — pricing, часто задаваемые вопросы
Обоснование
Почему Nuxt 4
| Критерий | Обоснование |
|---|---|
| Auto-imports | Минимум boilerplate кода |
| File-based routing | Структура папок = маршруты |
| Layers | Переиспользование конфигураций |
| Modules ecosystem | Nuxt UI, Nuxt Charts, и др. |
| TypeScript | First-class поддержка |
Почему SPA для dashboard-приложений
| Критерий | Обоснование |
|---|---|
| Целевая аудитория | Авторизованные пользователи (не нужен SEO) |
| Интерактивность | Dashboard-приложения с частыми обновлениями |
| Простота | Нет сложностей с hydration |
| Деплой | Статические файлы, любой CDN |
Почему SSR для динамических приложений с SEO
| Критерий | Обоснование |
|---|---|
| SEO + динамика | Индексация поисковиками + актуальные данные |
| Персонализация | Контент зависит от пользователя или запроса |
| Частые обновления | Данные меняются слишком часто для SSG |
| Open Graph | Динамические превью для каждой страницы |
| Первый рендер | HTML готов на сервере, быстрый FCP |
Почему SSG для статических сайтов
| Критерий | Обоснование |
|---|---|
| SEO | Полноценная индексация поисковиками |
| Скорость | Максимально быстрый First Contentful Paint |
| Core Web Vitals | Отличные показатели LCP, CLS, FID |
| Шаринг | Корректные Open Graph превью в соцсетях |
| Деплой | Статические файлы с минимальным TTFB |
| Безопасность | Нет серверной логики — нет уязвимостей |
| Стоимость | Дешёвый хостинг на любом CDN |
Структура проекта (Nuxt 4)
app-name/
├── app/ ← Код приложения
│ ├── components/
│ ├── composables/
│ ├── layouts/
│ ├── pages/
│ ├── plugins/
│ ├── stores/
│ ├── types/
│ └── app.vue
├── public/ ← Статика
├── nuxt.config.ts
└── package.json
Важно: В Nuxt 4 весь код приложения в папке app/.
Конфигурация
SPA для dashboard-приложений
// nuxt.config.ts
export default defineNuxtConfig({
ssr: false, // SPA режим
devtools: { enabled: true },
modules: [
'@nuxt/ui',
'@pinia/nuxt',
],
components: [
{
path: '~/components',
pathPrefix: false,
},
],
compatibilityDate: '2025-01-21'
})
SSG для лендинга и маркетинговых страниц
// nuxt.config.ts
export default defineNuxtConfig({
// SSR включен для генерации статики
ssr: true,
// Все маршруты будут предрендерены при сборке
nitro: {
prerender: {
routes: ['/'],
crawlLinks: true, // автоматически находит все ссылки
},
},
// Опционально: указать конкретные маршруты
routeRules: {
// Статические страницы (SSG)
'/': { prerender: true },
'/pricing': { prerender: true },
'/features': { prerender: true },
'/blog/**': { prerender: true },
'/stories/**': { prerender: true }, // истории успеха
'/about': { prerender: true },
'/contact': { prerender: true },
// Динамические страницы (если нужно)
'/api/**': { cors: true },
},
modules: [
'@nuxt/ui',
'@nuxt/content', // для блога и маркетинговых страниц
'@nuxt/image', // оптимизация изображений
],
// SEO конфигурация
site: {
url: 'https://example.com',
name: 'Platform',
},
compatibilityDate: '2025-01-21'
})
Структура лендинга с маркетинговым контентом
landing/
├── app/
│ ├── components/
│ │ ├── landing/
│ │ │ ├── Hero.vue
│ │ │ ├── Features.vue
│ │ │ ├── Pricing.vue
│ │ │ └── Testimonials.vue
│ │ └── blog/
│ │ ├── PostCard.vue
│ │ └── PostList.vue
│ ├── pages/
│ │ ├── index.vue # Главная
│ │ ├── pricing.vue # Тарифы
│ │ ├── features.vue # Возможности
│ │ ├── about.vue # О компании
│ │ ├── blog/
│ │ │ ├── index.vue # Список статей
│ │ │ └── [slug].vue # Страница статьи
│ │ └── stories/
│ │ ├── index.vue # Истории успеха
│ │ └── [slug].vue # Конкретная история
│ └── app.vue
├── content/
│ ├── blog/ # Статьи блога (Markdown)
│ │ ├── how-to-start.md
│ │ └── best-practices.md
│ └── stories/ # Истории успеха (Markdown)
│ ├── restaurant-a.md
│ └── cafe-b.md
├── public/
│ └── images/
├── nuxt.config.ts
└── package.json
Команды сборки
SPA (dashboard-приложения)
# Разработка
pnpm dev
# Сборка для продакшена
pnpm build
# Результат в .output/public/ — статические файлы
SSG (landing)
# Разработка
pnpm dev
# Сборка с предрендерингом всех страниц
pnpm generate
# Результат в .output/public/ — полностью статический сайт
# Каждая страница = отдельный HTML файл с полным контентом
Последствия
Положительные
- Единый фреймворк для всех приложений
- Современный DX с auto-imports
- Простой деплой статики
- Использование мощной модульной системы
- SSG для лендинга: отличный SEO, быстрая загрузка, корректные Open Graph
- Nuxt Content: удобное управление маркетинговым контентом в Markdown
Отрицательные
- Нет SEO для dashboard-приложений (не критично — они за авторизацией)
- При обновлении контента лендинга требуется пересборка (решается через CI/CD)
Hybrid Rendering и Route Rules
Nuxt 4 поддерживает гранулярное управление рендерингом на уровне маршрутов через routeRules. Это позволяет комбинировать SSR, SSG и SWR в одном приложении.
Stale-While-Revalidate (SWR)
Для контента, который обновляется, но не требует мгновенной актуальности:
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// Статические страницы — генерируются при сборке
'/': { prerender: true },
'/about': { prerender: true },
// Блог — SWR с ревалидацией каждый час
'/blog/**': { swr: 3600 },
// API — кэширование на 10 минут
'/api/public/**': { cache: { maxAge: 60 * 10 } },
// Dashboard — чистый SSR (актуальные данные)
'/dashboard/**': { ssr: true },
// SPA-зоны — без серверного рендеринга
'/admin/**': { ssr: false },
},
})
Incremental Static Regeneration (ISR)
ISR позволяет обновлять статические страницы по запросу, без полной пересборки:
routeRules: {
'/products/**': {
swr: true, // отдаёт кэш, обновляет в фоне
cache: {
maxAge: 60 * 60, // кэш на 1 час
},
},
}
Когда что использовать
| Режим | Когда | Пример |
|---|---|---|
prerender: true | Контент не меняется между деплоями | Landing, About, Pricing |
swr: N | Контент обновляется, допустима задержка N секунд | Блог, каталог |
cache: { maxAge: N } | API-ответы, допустим кэш | Публичные API |
ssr: true | Нужны актуальные данные и SEO | Профили, списки |
ssr: false | SPA-зона за авторизацией | Dashboard, Admin |