Введение

В этой небольшой статье мне бы хотелось рассказать о такой концепции как Layers в Nuxt 3, как её реализовываю я в своих проектах и почему я считаю это важным. Я покажу два примера: один демонстрирует разделение проекта на несколько слоев, а другой – разделение нескольких фронтендов по разным слоям. Желание написать статью об этом возникло после того как я не нашёл достаточное количество реальных примеров и статей на русском языке по использованию слоев.

Проблема, которая привела меня к Layers

Изначально я знал о концепции Layers в Nuxt 3, но не использовал её, считая излишней и не особо понятной. Но однажды, обнаружив себя копающимся в папке components, в которой было не менее шести подпапок, каждая с 10-30 компонентами, я понял, что что-то явно пошло не так. Я решил разбить свой проект на несколько слоев, но так чтобы избежать зависимости одного слоя от другого. Спустя некоторое время я пришёл к такой структуре:

  1. Base: В этом слое находятся общие компоненты сайта, такие как шапка, футер, лэйауты, композаблы и утилиты, используемые по всему проекту, а так же главная страница, страница пользовательского соглашения и т.д.

  2. User: Слой, отвечающий за работу с авторизацией, профилем пользователя и всем, что касается пользователя напрямую.

  3. Order: Всё, что касается заказов на сайте: страница создания заказов, список заказов пользователя, список всех заказов на сайте и т.д.

  4. Chat: Страница чата между пользователями. На этом же слое реализована логика работы с вебсокетом.

  5. UI: Из-за разросшегося Base слоя было принято решение вынести все UI компоненты в отдельный слой. Он нужен для того, чтобы 20 компонентов, касающихся форм, модальных окон и карточек, не засоряли базовый слой, в котором находятся более глобальные части и страницы приложения.

Главные преимущества, которые я ощутил при использовании такого подхода, это, во-первых, удобство работы над конкретной частью приложения. Если мне нужно обновить авторизацию, я не ищу компоненты/страницы/компосаблы по всему проекту, а иду к определённому слою и работаю исключительно в нём, не затрагивая остальные. Во-вторых, каждому слою можно прописать свою конфигурацию.

Cтруктура проекта:

├── layers/
│   ├── base/
│   │   ├── assets/
│   │   │   ├── fonts/
│   │   │   └── styles/
│   │   ├── components/
│   │   ├── composables/
│   │   ├── pages/
│   │   ├── stores/
│   │   ├── utils/
│   │   └── nuxt.config.ts
│   ├── chat/
│   │   ├── components/
│   │   ├── composables/
│   │   ├── pages/
│   │   ├── stores/
│   │   └── nuxt.config.ts
│   ├── order/
│   │   ├── components/
│   │   ├── pages/
│   │   ├── stores/
│   │   ├── specialist/
│   │   └── support/
│   ├── ui/
│   │   ├── components/
│   │   └── nuxt.config.ts
│   └── user/
│       ├── components/
│       ├── composables/
│       ├── middleware/
│       ├── pages/
│       ├── stores/
│       └── nuxt.config.ts
├── app.vue
├── error.vue
├── nuxt.config.ts
└── tsconfig.json

В главном nuxt.config.ts файле у меня прописано следующее:

extends: [
  "./layers/base",
  "./layers/ui",
  "./layers/order",
  "./layers/user",
  "./layers/chat"
],

// Исключительно для удобства при импортировании
alias: {
  "@": "./",
  base: "~/layers/base",
  ui: "~/layers/ui",
  order: "~/layers/order",
  user: "~/layers/user",
  chat: "~/layers/chat",
}

Проблема с которой я столкнулся

Если в двух разных слоях есть компонент с одинаковым названием, то в автоимпорт попадет только один. Это создаёт опасность случайно назвать компонент точно так же, как в другом слое, и не понять, почему всё работает неправильно. В попытках найти решение проблемы я решил отключить автоимпорт во всех слоях, но чтобы не терять преимущество от использования автоимпорта, я сделал в каждом слое внутри папки components папку global. Из неё все компоненты доступны для автоимпорта по всему приложению, а компоненты вне этой папки необходимо импортировать напрямую. Чтобы реализовать такую логику в каждом внутреннем nuxt.config.ts нужно прописать следующее:

components: [
  {
    path: "~/layers/base/components/global",
    pathPrefix: false,
    global: true
  }
]

Несколько сайтов на базе одного API

Перед нашей командой стояла задача сделать несколько сайтов, которые бы обращались к одному API, имели бы общие компоненты, композаблы и утилиты. Реализовать подобное решили через Layers, где каждый слой - отдельный сайт.
Структура следующая:

├── composables/
├── components/
├── services/
├── layers/
│   ├── site-1/
│   ├── site-2/
│   └── site-3/

В .env файле есть параметр, отвечающий за текущий сайт, например VITE_NUXT_LAYER=site-1. Он нужен для того чтобы в nuxt.config.ts прописать путь к необходимому сайту:

extends: ["./layers/" + import.meta.env.VITE_NUXT_LAYER]

После этого каждый разработчик прописывает необходимое ему название сайта и занимается разработкой исключительно внутри одного слоя, не затрагивая работу других.

Заключение

Использование Layers в Nuxt 3 позволяет значительно улучшить структуру и управляемость крупными проектами. Разделение на слои помогает избежать излишних зависимостей и облегчает работу над отдельными частями приложения.

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

Документация Layers Nuxt

Комментарии (6)


  1. francyfox
    24.07.2024 03:58

    Layers это не особо новая фича. Тока у нее ведь более простое название, монорепка. По сути подход не предлагает ничего нового и можно просто решить проблему реорганизацией структуры.


    1. davidaganov Автор
      24.07.2024 03:58

      да, ничего нового, просто я долго работал на второй версии и после перехода на третьею версию долго избегал некоторые подходы по причине того, что не понимал их смысла (те же компосаблы я избегал после опыта с миксинами во вью 2). поэтому статейка так, банально чтобы гуглилось на русском по этой теме, а то кроме документации толком не найти ничего


  1. detailcore
    24.07.2024 03:58

    Интересное решение с разными сайтами, возьму на заметку.

    Если не ошибаюсь, то подобный поход (как в 1ом случае, когда в каждой основной папке есть свои компасоблы и компоненты) называется модульной архитектурой, по крайней мере так пишет vue faq https://vue-faq.org/ru/development/architectural-patterns.html


  1. orlovec
    24.07.2024 03:58

    Спасибо! Мне было полезно. Знал про слои, но так использовать даже не предполагал.


  1. director-rentv
    24.07.2024 03:58

    Честно говоря, автоимпорт очень злое зло. Ещё приемлемо с префиксами пути, но без - потенциальный отложенный выстрел в куда вам больше нравится. Был опыт поддержки проекта с автоимпортами и регулярно менявшейся командой. Всего около десятка компонентов с одинаковым названием, но разными путями, а как замучались изучать, где какой должен быть по дизайну и задумкам окологодовалой давности...

    А слои классная тема, если я ничего не путаю, их вообще можно выносить в сторонние репозитории и шарить по нескольким репозиториям


    1. davidaganov Автор
      24.07.2024 03:58

      да, был такой опыт с автоимпортами в проекте с несколькими разрабами, в этом юзаю его потому что я тут один единственный и незаменимый, так сказать)) чисто для себя люблю их использовать