Архитектура

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 ecosystemNuxt UI, Nuxt Charts, и др.
TypeScriptFirst-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: falseSPA-зона за авторизациейDashboard, Admin

Связанные решения