
Вы знаете, как пишутся SPA на Laravel? Если коротко, не очень удобно. Конечно, можно использовать любой фронтенд-фреймворк. Традиционно принято работать со связкой Laravel + Vue.js.
Мы пишем весь фронтенд на Vue.js в resources/js, а Laravel используем как API.
Примерно вот так:
Vue.js
// resources/js/pages/Users.vue <template> <div v-for="user in users" :key="user.id"> <a :href="`/users/${user.id}`"> {{ user.name }} </a> <div>{{ user.email }}</div> </div> </template> <script> export default { data() { return { users: [] } }, methods: { async loadUsers() { const { data } = await this.$axios.get('/api/users');. this.users = data; } }, async beforeMount() { await this.loadUsers(); } } </script>
Laravel
// routes/api.php Route::get('/users', function index(User $user) { return $user->all(); });
То есть сначала мы создаем на бэкенде эндпоинт, а затем на фронте получаем с него данные через AJAX-запрос.
Удобно ли это? Смотря для кого. Фронтендерам не привыкать. AJAX на сегодня – самый классический способ получения данных с сервера. Но, если вы до этого много работали с Blade, вы понимаете, насколько это больше телодвижений.
Хотелось бы как с Blade, просто вернуть страницу уже с массивом данных, доступном на фронте как переменные:
return view('users', [ 'users' => $user->all() ]);
Какая разница? Она заметна, если нам нужно добавить еще какую-нибудь информацию во фронтенд-компонент. С Blade мы просто добавляем новую пару ключ-значение в массив данных. Но если Laravel – это просто API, нам нужно по-хорошему создавать отдельный эндпоинт. И т.д. и т.п.
От этого неудобства нас избавляет библиотека Inertia.js. С её помощью мы можем писать своё приложение так, будто бы мы пишем всё на Blade. Однако вместо него на стороне фронта использовать любимый фреймворк – Vue, React или Svelte.
Кроме Laravel, Inertia.js также может работать с бэкендом на Rails. И это только официально. Сторонние разработчики также добавляют поддержку других фреймворков и библиотек (например, Symfony или Yii2).
Далее все примеры будут на Vue.js и Laravel. Но при этом держите в уме, что всё это же можно делать и с другими вышеуказанными библиотеками.
Теперь на стороне сервера мы пишем
return Inertia::render('Users', [ 'users' => $user->all() ]);
А на фронте получаем данные как props.
props: { users: Array, },
Круто! Но это еще не всё.
Киллер-фича №2: Роутеры (Vue Router, React Router) больше не нужны. Теперь все страницы – это записи в routes и Vue-компоненты в папке resources/js/Pages (название папки кастомизируется). Всё, как с Blade, единственное, теперь вместо component.blade.php у вас Component.vue.
Ну и моё любимое: валидация на сервере. Больше не нужно отправлять ошибки AJAX-ом, а потом парсить их на фронте, где-то сохранять и таскать оттуда. Теперь можно просто расшарить ошибки из сессии в AppServiceProvider
Inertia::share([ 'errors' => function () { return Session::get('errors') ? Session::get('errors')->getBag('default')->getMessages() : (object) []; }, ]);
и получать их во Vue-компонентах как $page.errors.
<div v-if="$page.errors.first_name">{{ $page.errors.first_name[0] }}</div>
Тоже самое для уведомлений и любых других общих для всех компонентов данных.
При этом, данные можно шарить как синхронно (как в примере выше), так и "лениво", просто передавая в массив вместо самих данных колбэк, который их возвращает.
Inertia::share([ // Синхронно 'app' => [ 'name' => Config::get('app.name') ], // Лениво 'auth' => function () { return [ 'user' => Auth::user() ? [ 'id' => Auth::user()->id, 'first_name' => Auth::user()->first_name, 'last_name' => Auth::user()->last_name, ] : null ]; } ]);
Чтобы начать пользоваться, переходим в документации на страницу установки, выбираем нужные адаптеры – один для фронта, другой для бэка – и просто следуем инструкциям (1, 2).
Кстати, документация очень небольшая и удобная, всё наглядно и понятно, есть примеры на всех официально поддерживаемых фреймворках. Есть даже демо-приложение для того, чтобы посмотреть на всё в работе.
Я рассказал только об основных возможностях этой библиотеки. Тем не менее, если вы всё еще не впечатлены, я не знаю, как еще я могу вас удивить. Про остальные фишки вы можете узнать в той же документации. Среди них, удобная работа с ошибками в ходе разработки, кэширование локального состояния компонента и другие.
Но как и в любой бочке мёда, тут есть своя ложка дегтя.
Во-первых, Inertia.js должен контролировать рендеринг. Это значит, что нельзя просто перевести какой-то конкретный компонент на Inertia.js, нужно переносить всё приложение. По крайней мере, весь инстанс (если у вас микрофронтенды).
Во-вторых, тут нет Server-Side Rendering (SSR). Что, в принципе, неудивительно, ведь это просто прослойка между фронтом и бэком, а фронт как был SPA без SSR, так и остается. Но, возможно, эту функциональность добавят в будущем, разработчики говорят, что это возможно. Если вам кровь из носа нужен SSR, стоит посмотреть на бойца в противоположном углу ринга – Livewire. Но про него как-нибудь в другой раз.
Ну и в-третьих, Inertia.js – еще очень молодой проект. Последняя версия на момент написания статьи – v0.1.9. Поэтому смотрите сами, хотите ли вы использовать его в продакшене.
Тем не менее, я советую всем web-разработчикам попробовать и оценить самим этот замечательный инструмент.
