Олег Марков
5 правил использования Inertia с Vue и Laravel
Введение
Когда вы соединяете Laravel и Vue с помощью Inertia, вы получаете мощный инструмент для построения современных одностраничных приложений (SPA), избавляясь от многих классических проблем интеграции backend и frontend. Inertia позволяет использовать Laravel для серверной логики и рендера, а Vue — для интерфейса, предоставляя ощущение работы нативного SPA, без необходимости создавать REST или GraphQL API.
Сегодня я хочу поделиться с вами 5 основными правилами работы с Inertia, которые сделают ваш опыт проще, а проекты — надёжнее и легче поддерживаемыми. Каждый пункт я сопроводил примерами и объяснениями, чтобы вы могли сразу применить полученные знания на практике. По пути мы разберём архитектуру Inertia, структуру рендеринга, передачу данных, работу со стейтом и роутингом, уделяя внимание тонкостям, которые часто упускают новички.
1. Строим архитектуру: Разделяйте зоны ответственности
Грамотное разделение backend и frontend при работе с Inertia — основа вашего успеха. Важно сохранять логику бизнес-процессов и работы с данными на стороне Laravel, а отображение и обработку пользовательских интеракций — во Vue.
Почему это важно
Если смешивать логику обработки данных и отображения, ваш код быстро потеряет структурность и будет сложно поддаваться поддержке. Inertia помогает избежать дублирования методов между backend и frontend, но за архитектуру отвечаете вы.
Как это реализовать
Рассмотрим типичный маршрут:
// web.php в Laravel
use Inertia\Inertia;
Route::get('/dashboard', function () {
// Получаем данные на сервере
$users = User::all();
// Рендерим Vue-компонент через Inertia, передаём данные
return Inertia::render('Dashboard', [
'users' => $users // Данные отправляются во Vue
]);
});
Смотрите, в этом примере весь сбор данных происходит на стороне Laravel, а компонент Vue просто отображает их так, как нужно:
<!-- resources/js/Pages/Dashboard.vue -->
<template>
<div>
<h1>Пользователи</h1>
<ul>
<li v-for="user in users" :key="user.id">{{ user.name }}</li>
</ul>
</div>
</template>
<script setup>
import { defineProps } from 'vue'
// Здесь мы объявляем, что наш компонент ожидает проп 'users'
const props = defineProps(['users'])
</script>
Здесь Dashboard.vue ничего не знает о том, как были получены данные — он просто их рисует. Это упрощает сопровождение и вызывает меньше багов при масштабировании.
2. Передавайте только нужные данные
Не отправляйте во Vue больше информации, чем необходимо для отображения. Лучше собрать сразу всё, что требуется для одной страницы, чем устраивать дополнительные запросы или перегружать клиент избыточным payload.
Теория
В Inertia принцип "page props" означает, что все данные должны передаваться одной порцией при рендере страницы. Он похож на подход SSR (server-side rendering), но с сохранением SPA-ощущения.
На практике
Если ваша страница ожидает только имена и email пользователей, не отправляйте всю модель User:
// Вместо этого:
return Inertia::render('Dashboard', [
'users' => User::select('id', 'name', 'email')->get()
]);
Это минимизирует объём данных, передаваемых клиенту, а значит, ускоряет загрузку страницы и защищает от случайного раскрытия лишней информации.
Сериализация данных
Обратите внимание: когда вы передаёте Eloquent-коллекции или модели, Laravel автоматически их сериализует в массивы. Если нужно управление этим процессом — используйте ресурсы:
return Inertia::render('Dashboard', [
'users' => UserResource::collection(User::all())
]);
UserResource позволяет чётко указать, какие атрибуты попадут во Vue:
// app/Http/Resources/UserResource.php
public function toArray($request)
{
return [
'id' => $this->id,
'name' => $this->name,
// email и другие поля...
];
}
3. Используйте Inertia формирование ответов для унификации возврата
Inertia предлагает простые методы для формирования "SPA-like" ответов — используйте их всегда, когда работаете с переходами и формами. Это поможет унифицировать обработку событий (например, валидации ошибок или flash-сообщений).
Обработка форм и ошибок
Давайте рассмотрим, как корректно возвращать ошибки валидации:
use Illuminate\Http\Request;
use Inertia\Inertia;
public function store(Request $request)
{
$request->validate([
'title' => 'required|max:255',
]);
// ...сохраняем данные...
return redirect()->route('posts.index')->with('success', 'Пост добавлен!');
}
Во Vue компоненте можно отловить ошибки, так как Inertia передаст их через пропс errors:
<template>
<form @submit.prevent="submit">
<input v-model="form.title" />
<span v-if="errors.title">{{ errors.title }}</span>
<button type="submit">Создать</button>
</form>
</template>
<script setup>
import { useForm } from '@inertiajs/vue3'
const form = useForm({ title: '' })
const errors = form.errors
function submit() {
form.post('/posts')
}
</script>
Flash-сообщения
Вы также можете централизованно передавать flash-сообщения с сервера:
return redirect()->route('dashboard')->with('message', 'Вы успешно добавили пользователя!');
В Vue компонент всплывающее сообщение может брать из пропсов:
<template>
<div v-if="message" class="flash">{{ message }}</div>
</template>
<script setup>
import { defineProps } from 'vue'
const props = defineProps(['message'])
</script>
4. Держите клиентский роутинг под контролем с помощью Inertia Links
Очень важно использовать компонент <Link>
от Inertia для перехода между страницами, чтобы не было полного перезагрузки — это избавляет от потери состояния SPA.
Зачем использовать Inertia Link
Если вы воспользуетесь стандартным тегом <a>
, то браузер полностью перезагрузит страницу. Используйте компонент Inertia для плавных переходов:
<template>
<Link href="/dashboard" class="nav-link">Перейти в Дашборд</Link>
</template>
<script setup>
import { Link } from '@inertiajs/vue3'
</script>
Вот простой пример меню:
<template>
<nav>
<Link href="/profile">Профиль</Link>
<Link href="/settings">Настройки</Link>
</nav>
</template>
Этот подход сохраняет стейт вашего приложения, не выбрасывает пользователя из SPA "режима" и делает всё заметно быстрее, чем обычные переходы.
Передача данных с переходом
Можете передавать параметры через href
:
<Link :href="`/users/${user.id}/edit`">Редактировать</Link>
5. Не забывайте про "shared" данные
Иногда есть смысл сделать часть пропсов доступными на всех страницах — например, данные авторизации или flash-сообщения. Используйте Inertia::share для этого.
Как это сделать
В файле AppServiceProvider.php
или отдельном сервис-провайдере создайте метод, который добавит данные "по умолчанию" ко всем ответам Inertia.
// app/Providers/AppServiceProvider.php
use Inertia\Inertia;
use Illuminate\Support\Facades\Auth;
public function boot()
{
Inertia::share([
// Данные текущего пользователя
'auth' => fn () => [
'user' => Auth::user()
],
// flash-сообщение
'flash' => fn () => session('message')
]);
}
Теперь в любом компоненте Vue у вас будет доступ к этим prop'ам:
<template>
<div>
<span v-if="auth.user">Добро пожаловать, {{ auth.user.name }}</span>
<div v-if="flash">{{ flash }}</div>
</div>
</template>
<script setup>
import { defineProps } from 'vue'
// auth и flash приходят теперь на все страницы
const props = defineProps(['auth', 'flash'])
</script>
Это избавляет вас от необходимости явно прокидывать часто используемые данные в каждый отдельный рендер страницы.
Заключение
Работая с Inertia и используя Laravel и Vue, вы сочетаете лучшее из двух миров: мощный backend и современный реактивный frontend. Ключевые правила — это держать архитектуру чистой, минимизировать объём передаваемой информации, централизовать обработку ошибок и flash-сообщений, использовать Inertia Links для роутинга и делиться общими данными корректно через Inertia::share.
Если вы ещё не использовали Inertia в связке с Laravel и Vue — эти правила помогут встроить его в ваш процесс разработки и раскрыть его для себя по-настоящему эффективно.
Частозадаваемые технические вопросы по теме статьи и ответы на них
Как правильно использовать middleware с Inertia страницами?
Вы можете использовать все стандартные middleware Laravel, включая аутентификацию, проверки ролей и прочее. Для ограничения доступа к странице — просто применяйте middleware как обычно:
Route::get('/dashboard', function () {
// ...
})->middleware('auth');
Inertia автоматически учтёт редирект или 403/401 ответ. Для кастомной обработки неавторизованных ошибок используйте свой обработчик исключений.
Как реализовать lazy-загрузку данных на стороне клиента?
Если не хотите передавать все данные сразу, возвращайте минимальный набор, а затем используйте API-запросы (например, через Axios или Fetch) внутри Vue-компонентов для подгрузки остальных данных по требованию.
Как реализовать динамические параметры роутинга?
В Laravel определяйте маршрут с параметром, например:
Route::get('/users/{user}', function (User $user) {
return Inertia::render('UserProfile', ['user' => $user]);
});
Во Vue получение пропсов идентично другим страницам.
Можно ли использовать Vue Router совместно с Inertia?
Использовать Vue Router не рекомендуется — стандарный роутинг и управление историей берёт на себя Inertia (он использует History API). Если вы попытаетесь внедрять Vue Router, скорее всего получите конфликты с навигацией.
Как загрузить внешние библиотеки или плагины во Vue при использовании Inertia?
В main.js вашего Vue-приложения импортируйте сторонние библиотеки или плагины так же, как и в обычном SPA:
import { createApp, h } from 'vue'
import SomePlugin from 'some-plugin'
import { createInertiaApp } from '@inertiajs/vue3'
createInertiaApp({
// ... ваши настройки,
setup({ el, App, props, plugin }) {
const vueApp = createApp({ render: () => h(App, props) })
vueApp.use(plugin)
vueApp.use(SomePlugin)
vueApp.mount(el)
}
})
Это работает как обычно в Vue 3, совместимо с Inertia.