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

В Nuxt структура папок — это и есть конфигурация: положили файл в нужное место — получили поведение без единой строки настройки.
Суть: Nuxt построен на принципе «соглашения важнее конфигурации». Каждая папка имеет смысл: pages становятся маршрутами, components и composables авто-импортируются, server превращается в API, layouts оборачивают страницы. Знание структуры — половина владения Nuxt.

Главная мысль этого урока: в Nuxt вы почти не пишете конфигурацию. Вместо неё работают соглашения о расположении файлов. Это сильно отличается от чистого Vue, где вы вручную регистрируете роуты, импортируете компоненты и настраиваете сборку. В Nuxt достаточно положить файл в правильную папку.

Разберём ключевые директории. Обратите внимание: в Nuxt 4 исходный код по умолчанию живёт внутри папки app/ — это нововведение для более чистого разделения клиентского и серверного кода. В Nuxt 3 те же папки лежат в корне. Логика одинакова.

   my-nuxt-app/
   |- app/                <- исходники (Nuxt 4; в Nuxt 3 — в корне)
   |  |- pages/           <- файлы -> маршруты
   |  |- components/      <- авто-импорт компонентов
   |  |- composables/     <- авто-импорт useXxx()
   |  |- layouts/         <- обёртки страниц (шапка/подвал)
   |  |- middleware/      <- проверки перед переходом
   |  |- plugins/         <- код при старте приложения
   |  |- app.vue          <- корневой компонент
   |- server/             <- API и серверная логика (Nitro)
   |  |- api/             <- /api/* маршруты
   |- public/             <- статика как есть (favicon и т.п.)
   |- nuxt.config.ts      <- единственный конфиг
   |- package.json

Пройдёмся по смыслу. pages/ — самая важная папка: её структура напрямую превращается в маршруты приложения (об этом — целый раздел). components/ — ваши Vue-компоненты, которые становятся доступны в шаблонах без ручного импорта. composables/ — переиспользуемая логика в виде функций useXxx(), тоже авто-импортируемая. layouts/ — каркасы страниц: общая шапка, подвал, боковое меню. server/ — серверный код: API-маршруты, middleware, утилиты, которые выполняются только на сервере и никогда не попадают в браузер.

На практике большинство mismatch'ей всплывают не сразу, а в самый неудобный момент — когда вы подключаете дату публикации, относительное время («5 минут назад»), случайный баннер или код стороннего виджета. Все они недетерминированы по своей природе. Полезная привычка — при появлении предупреждения о гидратации в консоли сразу искать в компоненте обращения к времени, случайности и браузерным API. Чаще всего виноват именно один из них, и лечится это переносом такого кода в onMounted или оборачиванием в <ClientOnly>.

Как работает под капотом

При старте Nuxt сканирует эти папки и генерирует код «склейки» в скрытой директории .nuxt/. Например, из pages/ он строит конфигурацию Vue Router, из components/ — таблицу авто-импортов, из server/api/ — обработчики Nitro. Вы этого не видите, но именно поэтому всё «просто работает». Файл nuxt.config.ts — единственная точка явной настройки: там подключают модули, задают routeRules, переменные окружения и опции рендеринга.

Смоделируем, как Nuxt «понимает» назначение файла по его пути — простым маршрутизатором папок:

// Как Nuxt трактует файл по его расположению.
function classify(path) {
  if (path.startsWith("pages/"))       return "маршрут (route)";
  if (path.startsWith("components/"))  return "авто-импортируемый компонент";
  if (path.startsWith("composables/")) return "авто-импортируемый useXxx()";
  if (path.startsWith("server/api/"))  return "серверный API-обработчик";
  if (path.startsWith("layouts/"))     return "макет страницы";
  if (path.startsWith("middleware/"))  return "middleware маршрута";
  return "обычный файл";
}

const files = [
  "pages/index.vue",
  "pages/blog/[slug].vue",
  "components/TheHeader.vue",
  "composables/useCart.ts",
  "server/api/products.get.ts",
  "layouts/default.vue",
];

for (const f of files) {
  console.log(f.padEnd(28), "->", classify(f));
}

Попробуй сам ▶ — функция повторяет логику Nuxt: смысл файла определяется его путём, а не настройкой.

Частые ошибки

  • Класть серверный код в обычные папки. Секреты и обращения к БД должны жить в server/, иначе они попадут в браузерный бандл.
  • Искать роуты в конфиге. Маршруты задаются файлами в pages/, а не списком в nuxt.config.
  • Путать public/ и assets/. public/ отдаётся как есть, assets/ проходит через сборку (оптимизация, хеши).

Best practices

  • Держите компоненты мелкими и тематически сгруппированными в подпапках components/.
  • Выносите повторяющуюся логику в composables/ — это идиоматичный способ переиспользования в Nuxt.
  • Весь код, работающий с секретами и БД, — только в server/.

Итог: структура папок Nuxt — это его язык. Освоив назначение каждой директории, вы перестаёте искать «где настроить» и начинаете думать «куда положить файл». Дальше — самый наглядный пример соглашений: файловая маршрутизация.

Проверьте себя
1. Где в Nuxt следует размещать код, работающий с базой данных и секретами?
AВ папке pages/
BВ папке server/
CВ папке components/
DВ nuxt.config.ts
2. Как в Nuxt задаются маршруты приложения?
AСписком в nuxt.config.ts
BСтруктурой файлов в папке pages/
CЧерез ручную регистрацию в app.vue
DМаршруты задаются в package.json