Тема
React-острова в Blade vs Inertia + React
Архитектурный стандарт студии: когда сервер рендерит сайт с точечным React, а когда строится Inertia-приложение. Дизайн в обоих случаях приходит из Claude.ai/design (React + Tailwind) — отличается способ его посадки.
Суть подходов
Blade + React-острова. Сервер рендерит страницу целиком (Blade, кеш, SEO). React монтируется точечно — в конкретные блоки с состоянием: калькулятор, конфигуратор, живой фильтр. Каждый остров — самостоятельный компонент со своими props из data-атрибутов.
Inertia + React. Весь UI — React-страницы; Laravel остаётся контроллерами и доменом, но без REST-слоя: контроллер возвращает Inertia-страницу с props. Это SPA с серверным роутингом — приложение, а не сайт.
Это не конкурирующие технологии, а инструменты под разные классы продуктов. Ошибка — выбирать «что нам больше нравится»; выбирается класс продукта.
Политика студии (зафиксировано)
Дефолт — Blade + Alpine, острова точечно. Сервер рендерит сайт, React рендерит приложения внутри него.
Inertia — когда продукт ведёт себя как приложение: личный кабинет, B2B-портал, SaaS-дашборд. Страницы не кешируются, SEO не важен, состояние сквозное. И тогда правильный ход — не «CMS на Inertia», а отдельное Inertia-приложение рядом с ядром, использующее модули ядра (формы, настройки, домен) через их PHP-API.
Дисциплина количества островов. Когда остров — лёгкий способ «сделать красиво», их начинают плодить, и страница незаметно превращается в SPA на костылях с десятком точек гидрации. Правило: остров разрешён только блоку, которому нужно состояние (калькулятор, конфигуратор, живой фильтр, чат). Анимации, табы, аккордеоны — CSS/Alpine.
Сравнение по критериям
| Критерий | Blade + острова | Inertia + React |
|---|---|---|
| SEO, кеш страниц | ★★★ — нативно: сервер отдаёт HTML, page cache работает | ★ — нужен SSR-процесс; кеш страниц фактически теряется |
| Первая загрузка | Быстрая: HTML сразу, JS — только острова | Тяжелее: бандл приложения до первого рендера |
| Сквозное состояние (корзина видна везде, черновики, фильтры между экранами) | ★ — острова изолированы; общее состояние = костыли | ★★★ — единый store, состояние живёт между «страницами» |
| Насыщенные взаимодействия (drag&drop, живые таблицы, мастера) | Терпимо в рамках одного острова | ★★★ — родная стихия |
| Совместимость с Filament/Livewire | ★★★ — один стек, ничего не конфликтует | Livewire и Inertia на одной странице не смешивать |
| Сложность поддержки | Один шаблонный слой + точки React | Два полноценных мира: PHP + React-приложение |
| Тестирование | Feature-тесты покрывают страницы как обычно | Feature — только props; UI — отдельно (Vitest/Playwright) |
| Формы | Классика: FormRequest + redirect/flash | useForm Inertia — удобно, валидация та же FormRequest |
Матрица: тип проекта → подход
| Проект | Решение |
|---|---|
| Корпсайт, контент + SEO | Blade + Alpine; React не нужен вовсе или 1 остров (квиз/калькулятор) |
| Каталог, витрина магазина | Blade; острова: живой фильтр, корзина-виджет, конфигуратор |
| Лендинг с интерактивом | Blade + 1–2 острова |
| Личный кабинет с кастомным дизайном | Inertia-приложение рядом (/app), публичная часть остаётся Blade |
| Личный кабинет «функциональный», без дизайнерских требований | Третий путь: вторая Filament-панель — дешевле всего, дизайн из коробки |
| B2B-портал, SaaS-дашборд | Inertia + React с первого дня |
| Фриланс-биржа и подобное | Гибрид: публичные страницы (SEO) — Blade; кабинеты сделки/чаты — Inertia-приложение на том же ядре |
| Админка | Всегда Filament — Inertia-админку не строить |
Правило гибрида: граница проходит по auth. Всё до логина — сайт (Blade), всё после — приложение (Inertia или Filament-панель). Ядро (модели, сервисы, права) — общее.
Дизайн из Claude.ai/design — как садится в оба потока
Выход дизайна — React-компоненты на Tailwind. Дальше два конвейера:
| Blade + острова | Inertia | |
|---|---|---|
| Статические блоки | Конвертируются JSX → Blade-компоненты (механическая задача для Claude Code: разметка и классы сохраняются 1:1) | Используются как есть |
| Интерактивные блоки | Становятся корнем острова без переделки | Используются как есть |
| Tailwind-токены (цвета, шрифты, радиусы) | Общий tailwind.config — единая точка правды для Blade-классов и React | Тот же конфиг |
Практические правила конвейера:
- Конвертацию JSX → Blade делать сразу при посадке дизайна, не «временно оставим React для статики» — иначе статический блок тащит гидрацию без причины.
- Просить дизайн у Claude.ai/design поблочно (hero, карточка, форма), а не страницей — блоки чище ложатся и в Blade-компоненты, и в острова.
- Иконки из дизайна — в blade-icons/SVG-компоненты, не инлайн-копипаста по шаблонам.
Техническая обвязка островов (минимум)
- Один Vite-entry с реестром островов: контейнер
data-island="calculator"+data-props='{...json}', монтирование по наличию в DOM. - Ленивая гидрация: динамический
import()+IntersectionObserver— остров ниже фолда не грузит JS до появления на экране. - Props — только сериализуемые данные (id, массивы), не HTML; дальше остров сам ходит в API-роуты (
routes/api.php, throttle по стандарту). - Один остров = одна папка (
resources/js/islands/calculator/) со своим корневым компонентом; общих store между островами нет — потребность в общем store = сигнал, что это уже Inertia-приложение.
Красные флаги (когда выбор сделан неверно)
| Симптом | Диагноз |
|---|---|
| На странице 3+ острова и они хотят знать друг о друге | Это приложение — переводить раздел на Inertia |
| События между островами через window/шину | То же самое, костыльная стадия |
| Inertia-сайт, где 80% страниц — статьи и карточки | Контентный сайт на SPA: потерян кеш, SSR ради SEO — переплата; должен был быть Blade |
| Остров ради табов/аккордеона/анимации | Нарушение дисциплины: это CSS/Alpine |
| В Blade и React существует один и тот же UI-блок в двух копиях | Не проведена граница сайт/приложение — блок должен жить в одном мире |
| Кабинет на Inertia повторяет CRUD-таблицы «как в админке» | Дешевле было второй Filament-панелью |
Чеклист выбора перед стартом проекта
- Страницы должны индексироваться/кешироваться? → Blade для этих страниц, без вариантов.
- Есть сквозное состояние между экранами? → Inertia для этой зоны.
- Интерактив укладывается в 1–2 изолированных блока на страницу? → острова, больше — пересмотреть.
- Кабинет: есть дизайнерские требования? Нет → Filament-панель; да → Inertia рядом.
- Смешанный продукт? → гибрид по границе auth, общее ядро, без дублирования UI между мирами.
Выбор фиксировать в README проекта одной строкой («публичная часть — Blade+острова, кабинет — Inertia») — чтобы следующий разработчик и Claude Code не переизобретали границу.