image

Последние годы удалось поработать над несколькими большими и не очень проектами с использованием разных back-end и front-end фреймворков. Сталкивался с разными проблемами, возникавшими по мере роста приложения.

Сейчас могу сделать вывод из того, какие решения были удачными, а какие — не очень.
Используя накопленный опыт, задался целью собрать все лучшие решения, на мой взгляд, и создать свою основу для SPA.

Как создавать сайт на Laravel или что такое SPA, я рассказывать не буду. Такой информации хватает в интернете. Эта статья рассчитана на более-менее опытных разработчиков, поэтому некоторые детали я упущу.

Кому не терпится, в конце статьи ссылка на мой репозиторий на гитхабе.

Основными технологиями были выбраны Laravel и Vue.js + Vuex так как это мой основной стек.

Для быстрой разработки взял UI Kit — ElementUI.

Главная цель


Создать основание для среднего и большого проекта которое:

  • поможет избежать жёсткой сцепленности модулей
  • будет понятное для программиста c небольшим опытом
  • поможет избежать дублирования кода
  • будет легко расширяться
  • уменьшит время старта проекта
  • уменьшит время поддержки проекта и навигации по коду
  • заложит основу для написания качественного кода

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

Дальше каждый слой следует разделить сначала по функциональности, а потом уже каждый функциональный модуль — соответственно выбранному паттерну.

Вдохновляясь философией DDD, решил и фронт-енд и бэк-енд разделить на смысловые модули. Но это не те классические домены, что описывает Эванс. Его модель тоже не идеальна. В любом приложении со временем всегда появляются связи между компонентами — те же отношения между моделями.

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

На фронте создал каталог resources/js/modules, в котором и будут находиться разные модули. В каждом будет api — методы для работы с бэк-ендом, components — все компоненты и страницы, store — хранилище, и routes.

{moduleName}/
¦
+-- routes.js
¦
+-- api/
¦   L-- index.js
¦
+-- components/
¦   +-- {ModuleName}List.vue
¦   +-- {ModuleName}View.vue
¦   L-- {ModuleName}Form.vue
¦
L-- store/
    +-- store.js
    +-- types.js
    L-- actions.js

В resources/js создана папка core, где помещены основные компоненты системы.
Также есть папки bootstrap и includes для настройки дополнительных библиотек и утилит соответственно.

В проекте используется динамическая погрузка моделей. А именно в core/routes и в core/states мы подгружаем соответствующие файлы роутов и хранилищ автоматом (ничего прописывать не надо).

Вот пример как были подгружены store.js с разных модулей автоматически.

// Load store modules dynamically.
const requireContext = require.context('../../modules', true, /store\.js$/) 
 
let modules = requireContext.keys() 
    .map(file => 
        [file.replace(/(^.\/)|(\.js$)/g, ''), requireContext(file)] 
    )
    .reduce((modules, [path, module]) => { 
        let name = path.split('/')[0] 
        return { ...modules, [name]: module.store } 
    }, {})
 
modules = {...modules, core} 
 
export default new Vuex.Store({
    modules
})
 

На бэк-енде в каталоге app будут аналогичные модули. Каждый модуль будет содержать папки Controllers, Requests, Resources. Файл с роутами тоже вынесен сюда — routes_api.php.

{ModuleName}/
¦
+-- routes_api.php
¦
+-- Controllers/
¦   L--{ModuleName}Controller.php
¦
+-- Requests/
¦   L--{ModuleName}Request.php
¦
L-- Resources/
    L-- {ModuleName}Resource.php
 

Другие шаблоны проектирования типа events, jobs, polices и т.п. не будут включены в модули, так как они используются реже и логичнее их держать отдельным слоем.

Все манипуляции с динамической загрузкой модулей сделаны для того, чтобы между ними било минимальное зацепление. Это позволяет без последствий добавлять и удалять модули. Теперь можно сделать artisan make команду для создания такого модуля. С ее помощью мы сможем быстро наполнить проект нужными сущностями вместе с CRUD функциональностью.

Выполнив команду php artisan make:module {ModuleName}, у нас появятся все нужные файлы включая модель и миграции для работы полноценного CRUD. Вам останется только выполнить миграции php artisan migrate и все будет работать. Скорее всего вам понадобиться добавить дополнительные поля, поэтому перед миграцией не забудьте добавить их в модель, миграцию, а также, вывести во vue.



В данном шаблоне для аутентификации использовалась технология JWT-Auth, но возможно она избыточная и стоит переделать на Laravel Sanctum. В свою очередь На фронт-енде используется vue-auth, она позволяет легко управлять авторизацией пользователей и ролями.

В дальнейшем хотелось бы улучшить систему. Добавить глобальную шину событий, подключить websockets. Добавить тесты. Возможно в отдельных ветках сделать вариант с управлением ролями или создать ветки с другими UI Kit. Было бы хорошо, услышать рекомендации, замечания.

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

Весь код можно посмотреть в моем репозиторие на гитхабе.