Починаючи проєкт на React або Vue, кожного разу виникає питання, куди складати файли, бо у нас може бути багато компонентів, утилітарних функцій, стилів тощо. Тож давайте розберемося, які існують варіанти архітектури та для яких проєктів їх краще обирати.
Пласка архітектура
Найпростіша архітектура - це пласка, бо не потребує багато ресурсів. Достатньо створити в корені проєкту потрібні папки, і, наприклад, в components
скласти усі існуючі компоненти. Ця архітектура ідеально підійде для маленьких демо-проєктів або PoC (Proof of Concept).
/src
|-- /assets
| |-- /images
| |-- /styles
|-- /components
| |-- BaseButton.vue
| |-- BaseCard.vue
| |-- PokemonList.vue
| |-- PokemonCard.vue
|-- /composables
| |-- usePokemon.js
|-- /layouts
| |-- DefaultLayout.vue
| |-- AdminLayout.vue
|-- /plugins
| |-- translate.js
|-- /views
| |-- Home.vue
| |-- PokemonDetail.vue
|-- /router
| |-- index.js
|-- /store
| |-- index.js
|-- /utils
| |-- validators.js
|-- /tests
| |-- ...
|-- App.vue
|-- main.js
Модульна архітектура
Модульна архітектура дає можливість з легкістю розширювати функціонал та інкапсулювати усі пов'язані функції в одному місці. Якщо функція або будь-що інше не відноситься до модуля, існує папка core
, в якій можна створювати шарені файли. Також у майбутньому, використовуючи цю архітектуру, зручно виносити модулі в окремі мікросервіси.
/src
|-- /core
| |-- /components
| | |-- BaseButton.vue
| | |-- BaseIcon.vue
| |-- /models
| |-- /store
| |-- /services
| |-- /views
| | |-- DefaultLayout.vue
| | |-- AdminLayout.vue
| |-- /utils
| | |-- validators.js
|-- /assets
| |-- /images
| |-- /styles
| |-- /scss
|-- /plugins
| |-- translate.js
|-- /tests
|-- /modules
| |-- /pokemon
| | |-- /components
| | | |-- PokemonThumbnail.vue
| | | |-- PokemonCard.vue
| | | |-- PokemonListTemplate.vue
| | | |-- PokemonDetailTemplate.vue
| | |-- /models
| | |-- /store
| | | |-- pokemonStore.js
| | |-- /services
| | |-- /views
| | | |-- PokemonDetailPage.vue
| | |-- /tests
| | | |-- pokemonTests.spec.js
| |-- /search
| | |-- /components
| | | |-- SearchInput.vue
| | |-- /models
| | |-- /store
| | | |-- searchStore.js
| | |-- /services
| | |-- /views
| | |-- /tests
| | | |-- searchTests.spec.js
|-- App.vue
|-- main.ts
|-- router.ts
|-- store.ts
Feature Sliced Design
Feature Sliced Design - архітектура, яка дозволяє створювати та розширювати великі та довгострокові проєкти. Використовуючи цей варіант, треба обережно та обдумано вирішувати, куди покласти той чи інший файл, але при цьому Feature Sliced Design дає змогу структурувати файли так, щоб не мати їх десятками та сотнями в одній папці. Головний її підхід в наявності багатьох шарів:
- app - глобальні файли, наприклад, стилі, провайдери, роутер тощо
- pages - сторінки для відображення всіх сутностей, фіч та віджетів, які можуть мати свої власні стили, функції тощо
- entities - папка для бізнес сутностей, таких як
User
,Order
,Product
тощо; іншими словами, для всього, що може створювати та редагувати користувач сайту - features - зазвичай це папка, яка відповідає за компоненти, наприклад, для відправлення коментарів, додавання до кошика або пошук користувачів, але можуть бути і звичайні
js
чиts
файли - widgets - папка для комбінування сутностей та фіч в цілісні блоки інтерфейсу, такі як
IssueList
абоUserProfile
- shared - папка для всього, що не пов'язано ні з чим попереднім, ідеально підходить для файлів, які можуть використовуватися по всьому проєкту, наприклад, UI компоненти, глобальні
hook
/composables
,utils
тощо
/src
|-- /app
| |-- App.vue
| |-- main.js
| |-- app.scss
|-- /pages
| |-- Home.vue
| |-- PokemonDetailPage.vue
|-- /widgets
| |-- UserProfile.vue
| |-- PokemonStatsWidget.vue
|-- /features
| |-- pokemon
| | |-- CatchPokemon.vue
| | |-- PokemonList.vue
| |-- user
| | |-- Login.vue
| | |-- Register.vue
|-- /entities
| |-- user
| | |-- userService.js
| | |-- userModel.js
| |-- pokemon
| | |-- pokemonService.js
| | |-- pokemonModel.js
|-- /shared
| |-- ui
| | |-- BaseButton.vue
| | |-- BaseInput.vue
| | |-- Loader.vue
| |-- lib
| | |-- api.js
| | |-- helpers.js
|-- /assets
| |-- /images
| |-- /styles
|-- /router
| |-- index.js
|-- /store
| |-- index.js
|-- /tests
| |-- featureTests.spec.js
Мікрофронтенди
Мікрофронтенди - це частини одного великого проєкту, які можуть бути написані на різних фреймворках та збиратися на одній сторінці. Вони зручні тим, що різні люди, або навіть команди, можуть працювати над різними частинами додатка, не заважаючи один одному. Звичайно, в середині мікрофронтенду ви можете мати структуру папок вищевказаних архітектур.
Головна ідея - це мати один ентрі поінт для всіх мікрофронтендів, який буде керувати всіма ними. Кожен мікрофронтенд працює самостійно та може деплоїтись незалежно від інших.
Такий підхід ідеально підійде для великих та складних проєктів із багатьма командами, де кожна з них може зосередитися на розробці окремих фіч, не впливаючи на роботу інших, та використовувати різні технології.
Висновок
Для кожного проєкту треба підібрати влучну архітектуру, яка не буде йому шкодити, адже не для всіх може підійти, наприклад, Feature Sliced Design або модульна архітектура.
Архітектура | Плюси | Мінуси |
---|---|---|
Пласка | Легко реалізувати, мінімальні налаштування | Важка у масштабуванні, ускладнюється з ростом проєкту |
Модулі | Легка у масштабуванні, інкапсульовані функції | Можливі дублікати файлів, може стати складною |
Feature Sliced Design | Наявність багатьох шарів, чітка структура | Може бути складна для розуміння, потребує планування |
Мікрофронтенди | Незалежність від інших частин додатку | Висока складність |
Стаття написана на основі матеріалу How to Structure Vue Projects.