Архитектура большого, масштабного энтерпрайз приложения на VueJs

Архитектура большого, масштабного энтерпрайз приложения на VueJs

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

  1. Как структурировать модули приложения, поддерживая гибкость и масштабируемость архитектуры
  2. Как обрабатывать HTTP запросы
  3. Как управлять состоянием приложения
  4. Как обрабатывать исключения и ошибки приложения
  5. Как логировать данные в системе (вести логи важных событий приложения)

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

Благодаря Vue CLI 3 первоначальная настройка проекта занимает минимум времени. Однако, как бы не был крут Vue Cli 3, начальная настройка не решает все вышеперечисленные проблемы.

Архитектуру своих приложений я всегда стараюсь разделить на 3 слоя:

  • UI слой (пользовательский интерфейс) - слой, отвечающий за отображение представления пользователю. Он состоит из компонентов пользовательского интерфейса приложения.
  • Слой бизнес-логики - содержит всю важную логику приложения, которую мы часто именуем сервисамы.
  • Слой состояния приложения - общее состояние приложения и управление им.

Изучив материалы из готовых, доступных решений, я нашел множество способов структурирования файлов в проекте, например: папка-одного-типа (сущности), или папка-одной-функции (то есть, группировка сущностей по задаче, которую они решают). И я позаимствовал их идею, немного модифицировав её под собственные задачи. Я взял за основу схему структурирования, основанную на именовании папок, и структурированию файлов, решающих одну задачу, или тесно связанных с ней.

Пример этой структуры вы можете увидеть на картинке: 1_W3w4iY0M9EX5aKtdlEGfkg

В корневом каталоге будут находиться папки/файлы, созданные с помощью Vue CLI. В добавок к этому я добавил файлы окружений для среды разработки и продакшена (.env и .env.production), рекомендованные Vue CLI для управления различными конфигурациями окружения в приложении и упрощения процесса деплоя.

Папка src:
В папке src находится всё приложение. Эта папка содержит весь исходный код приложения, а также стили, файлы окружения и точку входу в приложение - main.js.

assets:
Содержит одну статику: файлы/изображения.

environment:
В ней находится файл environment.js. Мы можем получить доступ к переменным окружения, используя глобальный вызов process.env, но это может привести к ошибкам в будущем. Поэтому, я считаю, что должен быть общий интерфейс, через который мы можем получить доступ/ограничить доступ к переменным окружения.

plugins:
В этой папке будут размещены плагины Vue.

main.js:
Этот файл отвечает за загрузку приложения Vue и его компонентов.

Папка app:
В эту папку мы будем помещать папки, сгрупированные по конкретной задаче (по задаче, которую решают, или функции, которую выполняют). Она также будет содержать общую папку shared, в которой будут находиться: общие компоненты, конфиги, директивы, фильтры, сервисы и т.д. Кроме того, папка app будет содержать в себе еще 3 дополнительных файла:

  • app-routes.js:
    Этот файл будет отвечать за подключение всех маршрутов из функциональных модулей (разделяя приложение на модули, я предпочитаю называть их функциональными модулями). Он также будет иметь некоторые системные маршруты, необходимые для разработки и отладки.

  • app-state.js:
    Все настройки, связанные с управлением состоянием приложения будут осуществляться в этом файле. Например, конфигурация, настройка и подключение модулей, связанное с Vuex, будет выполнено здесь. Все состояния из различных функциональных модулей будут объединены здесь и сконфигурированы с системой управления состоянием.

  • app.vue:
    Это корневой компонент, который будет содержать основной шаблон приложения (представление).

Функциональные модули

Структура папок приложений разделена по функциям, или задачам, и, по сути, они и называются функциональными модулями. Корневой частью функционального модуля будут вложенные компоненты (подкомпоненты), вместе с тестами и общей (shared) папкой. Каждый функциональный модуль также будет иметь свои маршруты, состояние и основной файл компонента. Например, в функциональном модуле User, представлен компонент списка пользователей user-list и компонент конкретного экземпляра пользователя uset-item. А user-routes.js будет содержать маршруты, которые относятся конкретно к модулю User. Файл user-state.js будет включать в себя все настройки состояния пользователей и логику их обработки.

общая папка (shared):
Одна shared-папка будет находиться на уровне приложения, и, при этом, каждый функциональный модуль может также иметь свою собственную shared папку, на каждом шаге вложенности комонентов, конкретизируя область сущностей, для которой она является общей. Ключевое отличие между ними заключается в том, что shared папка в корнейвой папки приложения будет содержать общие вещи для всего приложения глобально, а shared папка на уровне модуля будет содержать вещи в рамках конкретного модуля.

components:
Эта папка будет содержать общие компоненты. Компоненты, которые будут входить в состав различных функциональных модулей или других компонентов. Например, это Header, Footer, Navigation и т.д.

config:
Эта папка будет содержать настройки, связанная с API, например, константы, конфигурационные параметры и т.д.

директивы directives:
Эта папка будет содержать общие директивы. Корневая shared папка приложения будет содержать директивы общего пользования на уровне всего приложения, а shared папка конкретного модуля будет содержать только директивы общего использования конкретного модуля.

Фильтры filters:
Эта папка будет содержать общие фильтры. Общие фильтры всего приложений будут находиться в корневой папке shared, а фильтры модулей - в папке shared конкретного модуля.

Сервисы services:
Большинство людей не понимают, что такое сервисы. Если говорить просто, то сервисы содержат бизнес-логику, хелперы или обработчики HTTP запросов, которые не зависят от логики представления пользовательского интерфейса (UI). Большинство людей называют их утилитами, хелперами или сервисами. Я называю из сервисами, мне кажется это описание наиболее подходящее.

Состояние state:
Shared папка приложения будет хранить информацию о состоянии, которое будет доступно для общего пользования разными функциональными модулями. Общая shared папка на уровне функционального модуля будет знать только о состояние конкретного функционального модуля, и управлять только им.

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

Чтобы решить проблему такого рода, подобные состояния должны включаться в состав общего, глобального состояния приложения (shared), а не конкретного функционального состояния. Поэтому функциональный модуль будет содержать в себе только состояния, нужные только для локального использования внутри модуля. А глобальные состояния на уровне приложения будут являться частью общего состояния приложения, которое будет доступно для различных общих компонентов. Иначе, нет смысла выносить сору из избы состояния на уровень всего приложения, если оно используется только в контексте одного конкретного модуля или задачи.

Резюме

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

Итого, из этой статьи у вас в голове должна была зародиться идея того, как заложить правильную архитектуру для крупного приложения на Vue.js. Надеюсь, что эта статья помогла вам понять, как правильно структурировать файлы проекта, для больших приложений. В следующих статьях этой серии вы узнаете детали и уточнения подобной архитектуры.