Inertia.js – современный монолит
- воскресенье, 19 июля 2020 г. в 00:29:54
Вы знаете, как пишутся 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-разработчикам попробовать и оценить самим этот замечательный инструмент.