FrontBean — расширенная документация

Эта страница дополняет README и описывает проект подробнее: структуру папок, окружение, внутренние модули, паттерны, рецепты и тонкости эксплуатации.

  • Стек: Nuxt 4 (Vue 3 + TypeScript), Tailwind CSS 4, shadcn‑nuxt UI, @nuxt/image, @nuxt/icon, @nuxt/content, @nuxtjs/i18n, @nuxtjs/sitemap, ESLint + Prettier.
  • Бэкенд взаимодействие: собственный HTTP‑клиент поверх ofetch с единым источником заголовков и перехватчиками.
  • Типы API: генерация из OpenAPI схемы (@hey-api/openapi-ts) в shared/types.
  • Док‑раздел UI (/docs) включается только когда активирован флаг окружения NUXT_ENABLE_CONTENT=true. В продакшене по умолчанию раздел отключён.

Требования и запуск

Запуск с nuxt/content и без него

Раздел /docs и модуль @nuxt/content включаются только когда задано NUXT_ENABLE_CONTENT=true.

  • Dev с документацией: установить в .env NUXT_ENABLE_CONTENT=true и выполнить npm run dev.
  • Prod-сборка без документации: не задавайте флаг и выполните npm run build && npm run preview.
  • Node.js >= 21.7.2 (см. engines в package.json)
  • Любой пакетный менеджер: npm / pnpm / yarn / bun

Команды:

# Установка зависимостей
npm install

# Локальная разработка
npm run dev

# Сборка production
npm run build

# Предпросмотр собранного билда
npm run preview

# Генерация типов из OpenAPI
npm run generate:openapi-ts

Переменные окружения (.env)

Проект использует runtimeConfig Nuxt. Значения читаются на сервере (private runtime config) и не попадают в клиентский бандл.

  • NUXT_API_BASE — базовый адрес бэкенда (например, https://api.example.com)
  • NUXT_API_AUTH — строка для заголовка Authorization; автоматически добавляется только в dev или если base содержит «servertest»
  • NUXT_API_TOKEN — токен, который будет подставлен в заголовок X-Access-Token
  • NUXT_PORT — порт, на котором запуститься приложение
  • NUXT_HOST — хост, на котором запуститься приложение

Пример .env:

NUXT_API_BASE=https://api.example.com
NUXT_API_AUTH=Basic xxxxxx
NUXT_API_TOKEN=YOUR_TOKEN
NUXT_PORT=5173
NUXT_HOST=0.0.0.0

Тонкости:

  • Строки без лишних пробелов и кавычек. Для Basic/Token схем не добавляйте слово «Bearer», если оно уже включено.
  • Эти переменные не доступны на клиенте (public runtimeConfig их не содержит). Для клиентских запросов используйте серверные маршруты‑прокси.

Структура папок

Ниже упрощённое дерево с пояснениями основных каталогов и ключевых файлов.

frontBean/
├─ app/                         # Приложение Nuxt: страницы, макеты, компоненты, стили
│  ├─ app.vue                   # Корневой компонент приложения
│  ├─ assets/
│  │  └─ css/tailwind.css      # Входная точка Tailwind CSS 4
│  ├─ components/
│  │  └─ ui/
│  │     └─ button/
│  │        ├─ UIButton.vue    # Пример UI-компонента (shadcn-нэйминг, без префикса)
│  │        └─ button.ts       # Варианты/типы кнопок
│  ├─ layouts/
│  │  └─ docs.vue              # Макет для раздела UI-доков (dev-only)
│  ├─ middleware/                     # (не используется для скрытия /docs)
│  │  └─ ...
│  └─ pages/
│     └─ docs/
│        ├─ index.vue          # Точка входа UI-доков
│        └─ ui/
│           └─ buttons.vue     # Пример страницы с демо кнопок
│
├─ content/
│  └─ docs/
│     └─ index.md              # Эта расширенная документация (Nuxt Content)
│
├─ server/                      # Серверная часть (Nitro)
│  ├─ api/
│  │  └─ init.ts           # Агрегация стартовых данных из удалённого API
│  └─ utils/
│     └─ http.ts               # Кастомный HTTP-клиент на базе ofetch
│
├─ i18n/
│  └─ locales/
│     ├─ ru.json               # Русская локаль
│     └─ en.json               # Английская локаль
│
├─ shared/                      # Общие модули и сгенерированные типы
│  └─ types/                    # Результат генерации @hey-api/openapi-ts
│
├─ public/                      # Статика, шрифты, изображения
├─ modules/                     # (опционально) Пользовательские модули Nuxt
├─ lib/                         # Внутренние утилиты/библиотеки (если есть)
├─ configs/
│  └─ tsconfig.app.json        # Доп. tsconfig для области app/
│
├─ components.json              # Конфиг shadcn-nuxt (директория компонентов и др.)
├─ nuxt.config.ts               # Конфигурация Nuxt
├─ openapi-ts.config.ts         # Конфиг генерации типов из OpenAPI
├─ eslint.config.mjs            # ESLint конфигурация
├─ tsconfig.json                # Базовый TS-конфиг
└─ README.md                    # Краткая документация

Конфигурация Nuxt (nuxt.config.ts)

Ключевые моменты:

  • alias:
    • #shared → ./shared
    • #modules → ./modules
    • #server → ./server
    • #lib → ./lib
    • components → ./app/components/
  • modules: @nuxt/eslint, @nuxt/icon, @nuxt/image, shadcn-nuxt, @vueuse/nuxt, @nuxtjs/i18n, @nuxtjs/sitemap, @nuxt/content
  • css: ./app/assets/css/tailwind.css (Tailwind CSS 4 через Vite плагин @tailwindcss/vite)
  • i18n: локали ru/en, стратегия no_prefix, автоопределение языка с cookie i18n_redirected
  • runtimeConfig: apiBase, apiAuth, apiToken (private); public: { isDev }

HTTP‑клиент (server/utils/http.ts)

Класс HttpClient инкапсулирует $fetch с перехватчиками и единым источником заголовков. Экспортируется экземпляр serverHttp и вспомогательная функция httpRequest.

Особенности:

  • Базовый URL берётся из runtimeConfig.apiBase.
  • Заголовки собираются из defaults клиента + per-request, нормализуются и устанавливаются строго в хук onRequest.
  • Авто‑инъекции:
    • X-Access-Token ← runtimeConfig.apiToken (если не задан в запросе).
    • Authorization ← runtimeConfig.apiAuth (только в dev или если apiBase содержит «servertest»; регистронезависимо).
  • Поддержка перехватчиков onRequest, onResponse, onError на уровне клиента и конкретного запроса.
  • Гибкая обработка ответа: parseAs: 'json' | 'text' | 'blob' | 'arrayBuffer' | 'response' (raw Response через instance.raw).
  • Ошибки приводятся к ApiError со свойствами status, statusText, method, url, data, cause.

Пример использования в серверном обработчике:

import { defineEventHandler } from 'h3';
import { serverHttp, ApiError } from 'server/utils/http';

export default defineEventHandler(async (event) => {
  try {
    const data = await serverHttp.get('/api/example/', {
      params: { page: 1 }
    });
    return data;
  } catch (e) {
    if (e instanceof ApiError) {
      return { message: e.message, status: e.status, details: e.data };
    }
    throw e;
  }
});

Важно:

  • Не используйте serverHttp на клиенте: private runtimeConfig (apiBase/apiAuth/apiToken) недоступен на клиентской стороне. Для браузерных вызовов вызывайте ваши серверные маршруты (например, /api/...) или предусмотрите публичный прокси.
  • Если baseURL не задан — будет выброшен ApiError("Base URL is not defined"). Проверьте .env и переменные в окружении деплоя.

Серверные маршруты

GET /api/init

Агрегирует начальные данные параллельными запросами:

  • /api/configs/
  • /api/menus/
  • /api/feedback/

Возвращает объект: { configs, menus, feedback }. Ошибки ApiError преобразуются в JSON с корректным HTTP‑статусом.

Генерация типов из OpenAPI

Конфиг: openapi-ts.config.ts

  • input.path строится из ${NUXT_API_BASE}/api/schema.yaml
  • В запрос подстановки схемы прокидывается заголовок Authorization из NUXT_API_AUTH
  • Вывод: каталог shared/types
  • Плагины: @hey-api/typescript

Запуск:

npm run generate:openapi-ts

Советы:

  • При изменении схемы включён watch: true, но при проблемах с авторизацией перезапустите команду вручную.
  • Типы доступны через алиас #shared, например import type { SomeType } from '#shared/types/types.gen'.

Мультиязычность (@nuxtjs/i18n)

  • Локали: ru (по умолчанию), en
  • Стратегия: no_prefix — без префикса в URL
  • Файлы переводов: i18n/locales/ru.json, i18n/locales/en.json
  • Автоопределение языка: включено, cookie i18n_redirected, редирект только с корня (redirectOn: 'root')

Добавление новой локали:

  1. Создайте файл переводов в i18n/locales/<code>.json.
  2. Добавьте запись в nuxt.config.tsi18n.locales.
  3. При необходимости поменяйте defaultLocale.

SEO подсказки:

  • При стратегии без префикса учитывайте <html lang> и мета‑теги для корректной индексации.

UI, стили и иконки

  • Tailwind CSS 4 подключён через Vite плагин @tailwindcss/vite (см. nuxt.config.ts → vite.plugins).
  • shadcn-nuxt:
    • prefix: '' (компоненты без префикса)
    • componentDir: ./app/components/shadcn
    • настройки в components.json
  • @nuxt/icon — иконки через компонент <Icon name="..." /> (см. примеры в docs макете).
  • @nuxt/image — оптимизация изображений; используйте <NuxtImg> вместо <img>.

Пример использования UI кнопки:

<script setup lang="ts">
import UIButton from 'components/ui/button/Button.vue'
</script>

<template>
  <UIButton variant="primary" size="m">Отправить</UIButton>
</template>

Док‑раздел UI (/docs)

  • Макет: app/layouts/docs.vue — левое меню, слот контента.
  • Страницы примеров: app/pages/docs/**/*. В продакшене по умолчанию отсутствуют, если NUXT_ENABLE_CONTENT не задан или равен false.
  • Чтобы открыть локально: запустите npm run dev и перейдите на http://localhost:3000/docs.

Качество кода

  • ESLint: eslint.config.mjs (Vue + TS правила)
  • Prettier: форматирование кода
  • Devtools: включены (devtools.enabled = true) для удобной отладки

Рецепты

1. Добавить серверный эндпоинт

  1. Создайте файл, например server/api/users.get.ts.
  2. Используйте serverHttp для запроса к внешнему API.
import { defineEventHandler } from 'h3';
import { serverHttp } from '#server/utils/http';

export default defineEventHandler(async () => {
  return serverHttp.get('/api/users/');
});

2. Использовать HTTP‑клиент с перехватчиками

import { serverHttp } from '#server/utils/http';

serverHttp.get('/api/example/', {
  interceptors: {
    onRequest: ({ url, init }) => console.debug('→', init.method, url.toString()),
    onResponse: ({ response }) => console.debug('←', response.status),
    onError: ({ error }) => console.error('×', error)
  }
});

3. Добавить страницу

  • Создайте app/pages/my-page.vue. Nuxt автоматически добавит маршрут /my-page.

4. Добавить локаль

  • См. раздел «Мультиязычность». Не забудьте обновить i18n.locales и файл переводов.

5. Добавить UI‑компонент

  • Поместите компонент в app/components/ui/<block>/<Name>.vue и используйте через алиас components.

Тонкости и частые проблемы

  • 401/403 в dev: проверьте NUXT_API_AUTH и что dev режим действительно включён (на клиент Authorization не подставляется).
  • 401 в prod: заголовок Authorization автоматически НЕ подставляется. Настройте бэкенд или используйте серверные токены.
  • 500 от /api/init: проверьте доступность ${NUXT_API_BASE} и корректность путей /api/configs/, /api/menus/, /api/feedback/.
  • Base URL is not defined: убедитесь, что переменная NUXT_API_BASE задана в окружении процесса (PM2, Docker, сервер хостинга и т.д.).
  • CORS: выполняйте запросы к внешнему API из серверных обработчиков, а не напрямую из браузера.

Плагины Nitro: счётчики и sitemap

README описывает два плагина (вставка счётчиков/мета и подмена sitemap URL-ов). Если они отсутствуют в текущей ревизии проекта, ориентируйтесь на документацию:

  • counters.ts: hook render:response для вставки HTML‑фрагментов из /api/configs/ в head/body.
  • sitemap.ts: hook sitemap:resolved (@nuxtjs/sitemap) и подмена ctx.urls данными из /api/sitemaps/.

Полезные ссылки