Inertia.js: bridge entre Laravel e frontend moderno
1. Introdução ao Inertia.js e seu Papel no Ecossistema PHP
Inertia.js é uma abordagem inovadora para construir aplicações web modernas sem a complexidade de uma API REST dedicada. Diferente do Livewire, que mantém todo o estado no servidor, ou de frameworks como Vue e React puros que exigem APIs completas, Inertia atua como uma ponte entre o Laravel e o frontend, permitindo criar Single Page Applications (SPAs) de forma simplificada.
O conceito central é que você continua escrevendo seus controladores e rotas no Laravel, mas em vez de retornar views Blade, você retorna componentes frontend. A mágica acontece porque Inertia intercepta as requisições, serializa os dados e os envia como JSON para o frontend, que renderiza os componentes sem recarregar a página.
Para desenvolvedores PHP que trabalham com Laravel, Inertia oferece o melhor dos dois mundos: a produtividade do ecossistema Laravel com a experiência de usuário de uma SPA moderna.
2. Arquitetura e Funcionamento Interno
O fluxo de uma requisição Inertia começa no navegador, que faz uma requisição HTTP normal para uma rota Laravel. O Laravel processa a requisição normalmente, mas em vez de retornar uma view Blade completa, o controlador utiliza Inertia::render():
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Models\User;
class UserController extends Controller
{
public function index()
{
$users = User::all();
return Inertia::render('Users/Index', [
'users' => $users
]);
}
}
O papel do Inertia::render() é crucial: ele retorna uma resposta JSON contendo o nome do componente e os dados (props). No frontend, o adaptador Inertia (Vue, React ou Svelte) interpreta essa resposta e renderiza o componente correspondente, mantendo o estado da aplicação sem recarregar a página.
O gerenciamento de estado no frontend acontece sem a necessidade de uma API REST explícita. Cada requisição subsequente (via <Link> ou Inertia.visit()) segue o mesmo padrão: o Laravel processa, Inertia serializa, e o frontend atualiza apenas a parte necessária da interface.
3. Configuração Inicial no Laravel
Para começar, instale o pacote Inertia no Laravel:
composer require inertiajs/inertia-laravel
Em seguida, instale o adaptador frontend de sua escolha. Para Vue 3:
npm install @inertiajs/vue3
Crie o middleware HandleInertiaRequests:
php artisan inertia:middleware
Registre o middleware no app/Http/Kernel.php:
protected $middlewareGroups = [
'web' => [
// ... outros middlewares
\App\Http\Middleware\HandleInertiaRequests::class,
],
];
Configure o arquivo resources/views/app.blade.php como shell inicial:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
@vite('resources/js/app.js')
@inertiaHead
</head>
<body>
@inertia
</body>
</html>
4. Roteamento e Compartilhamento de Dados
As rotas no Laravel permanecem praticamente as mesmas. A diferença está no retorno dos controladores:
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\DashboardController;
Route::middleware(['auth'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
});
Para compartilhar dados globais (como o usuário autenticado), utilize o método Share() no middleware:
<?php
namespace App\Http\Middleware;
use Illuminate\Http\Request;
use Inertia\Middleware;
class HandleInertiaRequests extends Middleware
{
public function share(Request $request): array
{
return array_merge(parent::share($request), [
'auth' => [
'user' => $request->user() ? [
'id' => $request->user()->id,
'name' => $request->user()->name,
'email' => $request->user()->email,
] : null,
],
'flash' => [
'success' => session('success'),
'error' => session('error'),
],
]);
}
}
Dados específicos por requisição são passados como props no controlador:
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
use App\Models\Post;
class PostController extends Controller
{
public function show(Post $post)
{
return Inertia::render('Posts/Show', [
'post' => $post->load('author'),
'relatedPosts' => Post::where('category_id', $post->category_id)
->where('id', '!=', $post->id)
->limit(3)
->get()
]);
}
}
5. Componentes e Navegação no Frontend
No frontend, crie componentes Vue que recebem props tipadas. Exemplo de resources/js/Pages/Posts/Show.vue:
<template>
<Layout>
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<h2>Posts Relacionados</h2>
<ul>
<li v-for="related in relatedPosts" :key="related.id">
<Link :href="`/posts/${related.id}`">{{ related.title }}</Link>
</li>
</ul>
</Layout>
</template>
<script setup>
import { Link } from '@inertiajs/vue3';
import Layout from '@/Components/Layout.vue';
defineProps({
post: Object,
relatedPosts: Array
});
</script>
Para navegação sem recarregar a página, use o componente <Link>:
<template>
<Link href="/dashboard" class="nav-link">
Dashboard
</Link>
</template>
Gerenciamento de formulários com Inertia.post():
<template>
<form @submit.prevent="submit">
<input v-model="form.title" placeholder="Título" />
<div v-if="form.errors.title">{{ form.errors.title }}</div>
<button type="submit" :disabled="form.processing">
Salvar
</button>
</form>
</template>
<script setup>
import { useForm } from '@inertiajs/vue3';
const form = useForm({
title: ''
});
function submit() {
form.post('/posts');
}
</script>
6. Tratamento de Erros e Validação
O Laravel compartilha automaticamente os erros de validação através do objeto $errors:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
public function rules(): array
{
return [
'title' => 'required|string|max:255',
'content' => 'required|string',
];
}
}
No frontend, os erros ficam disponíveis no objeto form.errors ou através do componente Errors:
<template>
<div v-if="$page.props.errors.title" class="error">
{{ $page.props.errors.title[0] }}
</div>
</template>
Para flash messages, utilize a sessão compartilhada no middleware:
<?php
namespace App\Http\Controllers;
use Inertia\Inertia;
class PostController extends Controller
{
public function store(StorePostRequest $request)
{
Post::create($request->validated());
return redirect()->back()->with('success', 'Post criado com sucesso!');
}
}
No frontend, acesse a flash message:
<template>
<div v-if="$page.props.flash.success" class="alert alert-success">
{{ $page.props.flash.success }}
</div>
</template>
7. Boas Práticas e Integração com Outros Pacotes
Organize seus diretórios separando páginas e componentes:
resources/js/
├── Pages/
│ ├── Dashboard.vue
│ ├── Posts/
│ │ ├── Index.vue
│ │ └── Show.vue
│ └── Users/
│ └── Index.vue
├── Components/
│ ├── Layout.vue
│ ├── Button.vue
│ └── Modal.vue
└── app.js
Para depuração, utilize o Laravel Telescope que captura requisições Inertia perfeitamente:
composer require laravel/telescope
Combine Inertia com Rate Limiting quando necessário:
Route::middleware(['throttle:10,1'])->group(function () {
Route::post('/posts', [PostController::class, 'store']);
});
8. Limitações e Quando Evitar o Inertia.js
Inertia não é a melhor escolha para todos os cenários. Evite-o quando:
- Aplicações com muitas interações em tempo real: Se sua aplicação necessita de WebSockets constantes, uma API REST com WebSockets dedicados pode ser mais eficiente.
- Aplicações mobile ou third-party: Se você precisa expor uma API para clientes externos, uma API REST tradicional é obrigatória.
- Performance crítica: Em aplicações com milhares de componentes simultâneos, o overhead de serialização do Inertia pode impactar a performance.
- Migração gradual: Se você precisa migrar um Laravel tradicional para Inertia, faça-o de forma incremental, começando por páginas menos críticas.
Para projetos novos que se encaixam no perfil de CRUD tradicional com boa experiência de usuário, Inertia.js é uma escolha excelente que combina a robustez do Laravel com a fluidez de uma SPA moderna.
Referências
- Documentação Oficial do Inertia.js — Guia completo com exemplos de instalação, configuração e uso avançado
- Laravel News: Introdução ao Inertia.js — Artigo introdutório explicando os conceitos fundamentais
- Inertia.js Laravel - GitHub — Repositório oficial do pacote Laravel com issues e discussões
- Laravel Bootcamp: Inertia com Vue — Tutorial prático oficial do Laravel usando Inertia com Vue.js
- Laracasts: Inertia.js Series — Série de vídeos tutoriais sobre Inertia.js com exemplos práticos