В этом репозитории вы найдёте мой личный пример реализации динамических модальных окон в веб-приложениях на стеке Laravel + Inertia.js + Vue + Tailwind CSS.
Представленный подход должен отлично подойти проектам, практикующим DDD или его "облегчённые" формы (модульный монолит и т.п.), но в целом он подойдёт любому проекту, использующему Inertia.js для SPA-фронтенда в Laravel-приложении.
Мой подход не потребует дополнительных манипуляций с HTTP-заголовками, middleware или внедрения сторонних пакетов (кроме Axios на фронтенде). Вам даже не нужно прибегать к использованию глобальных данных Inertia через её HandleInertiaRequests middleware, и этот подход легко масштабируется.
Я написал подробный пост об этом в блоге на своём сайте, который тоже поможет вам лучше понять, как и зачем используется мой подход к реализации модальных окон в Laravel и Inertia.js.
- В командной строке перейдите в корень проекта
cp .env.example .env
composer install
npm install
npm run build
php artisan key:generate
php artisan migrate --seed
(используется база данных SQLite по умолчанию)php artisan test
— для тестирования
Запускать проект в Docker или через Laravel Herd и другие локальные серверы — на ваше усмотрение. Подробные инструкции по установке и запуску проекта на Laravel доступны в официальной документации фреймворка.
Модальные окна в большинстве случаев бывают двух типов: окно подтверждения действия и окно с формой ввода. Используя подход, представленный в этом репозитории, на фронтенде вы лишь добавляете "обёртку" для рендеринга модальных окон и задаёте базовые условия их отображения и разделения по типу, а контроль за содержимым этих модальных окон вы полностью делегируете бэкенду.
Несмотря на превосходные инструменты, которые нам дарят современные фронтенд-фреймворки и библиотеки, я убеждён, что фронтенд должен оставаться "тупым", и архитектурные решения приложения не должны подстраиваться под него (кроме исключительных случаев, разумеется). Поэтому практически всю динамическую часть кода модальных окон мы отдаём бэкенду, а фронтенд получает только готовые объекты данных, которые он рендерит соответствующим образом — в установленных условиях и ограничениях.
На фронтенде вам доступен конфигурируемый компонент-триггер, отвечающий за отправку XHR-запроса на сервер с помощью Axios. Он получает только URL эндпоинта, по которому делает запрос, а сервер отвечает JSON с данными нужного модального окна. Этот компонент можно стилизовать извне, и он имеет слот для добавления любого текста или иконки для кнопки.
Основная "обёртка" модального окна добавляется в главный layout в качестве компонента Vue. Для управления состоянием модального окна используется собственный composable, содержащий экспортируемое и "реактивное" состояние (state). Это позволяет управлять модальным окном из разных точек интерфейса, используя этот composable в качестве своего рода глобальной шины, не связанной с глобальным состоянием стрыницы Inertia.
Для рендеринга модальных окон в проекте есть два компонента: для подтверждения действия и для формы ввода. Компонент модальной формы ввода обслуживается собственным "конструктором" динамических форм, который рендерит любую комбинацию полей ввода, которые приходят вместе с изначальными значениями (заполненные или пустые) с бэкенда при вызове этого модального окна.
На бэкенде такие вызовы модальных окон будут приходить в любой стандартный контроллер и обрабатываться, как и любой HTTP-запрос в Laravel, а ответ будет формироваться из DTO со строгой типизацией и возвращаться в формате JSON. На фронтенде ответ затем обрабатывается в том же компоненте-триггере, который изначально вызывает модальное окно, а данные ответа передаются в глобальный Vue composable, содержащий "реактивные" параметры состояния.
Весь код, относящийся к модальным окнам, добавлен в директорию src/
в корне проекта, которая подключена к автозагрузке в качестве неймспейса Domain\
. В остальном это пустое стандартное Laravel-приложение, за исключением добавления middleware HandleInertiaRequests
, обязательного для работы Inertia.js на бэкенде.
Все взаимодействия происходят с фиктивным списком пользователей, который генерируется фабриками Laravel и сидируется соответствующей командой artisan.
В приложении нет никакой авторизации, так как это просто демо, не предназначенное для публичного применения в продакшене.
-
Чтобы проще было понимать логику, начинайте свой путь из файла
routes/web.php
, где указаны все эндпоинты приложения, включая те, которые обслуживают модальные окна. С них вы можете перейти в контроллеры и следовать добавленной мной подробной документации в коде. -
В этом демо я не применяю TypeScript для простоты восприятия кода разработчиками разных уровней подготовки и опыта. Но, если вы работаете с TypeScript, то, разумеется, вы сможете добиться строгой типизации и на фронтенде, сделав этот подход к реализации модальных окон ещё более отказоустойчивым.
-
На бэкенде, в неймспейсе
Domain\Admin\Users
вы найдёте классыCreateModal
иEditModal
. Связывать их контрактом или нет — решать вам, в зависимости от требований вашего проекта и команды. Технически это просто фабрики полей ввода для форм, и нехватку любого из их методов перехватят тесты.
Я использовал похожий подход к реализации модальных окон уже не один год в продакшене, в коммерческих клиентских проектах, но данная реализация — это его актуальная версия, и она была вдохновлена концепцией пакета InertiaUI/Modal от Паскаля Балье, известного разработчика в экосистеме Laravel.
Его подход предполагает глубокую интеграцию в жизненном цикле запроса в Inertia и дополнительную манипуляцию HTTP-заголовками и middleware в Laravel, но, на мой взгляд, это излишнее усложнение для большинства проектов. Поэтому, если вы хотите иметь меньше на одну зависимость в проекте и больше контроля, то, я надеюсь, вы найдёте мой более "лёгкий" вариант реализации модальных окон полезным.