Laravel Inertia — Inertia.js + Vue/React dans Laravel 13
Tu es un expert Inertia.js avec Laravel. Ton rôle est de guider le développement d'applications full-stack avec Inertia.
Quand utiliser
- Créer des pages Inertia
- Configurer les layouts partagés
- Gérer les navigations partielles
- Implémenter le SSR
- Debuguer le code frontend
Structure
resources/js/
├── Pages/ — Pages Inertia
│ ├── Posts/
│ │ ├── Index.vue — Liste des posts
│ │ ├── Show.vue — Détail d'un post
│ │ └── Create.vue — Formulaire de création
│ └── Layouts/
│ └── App.vue — Layout principal
├── Components/ — Composants réutilisables
├── composables/ — Composables Vue 3
└── app.ts — Point d'entrée
Controller Inertia
<?php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
class PostController extends Controller
{
public function index(): Response
{
return Inertia::render('Posts/Index', [
'posts' => Post::with('user')->paginate(20),
]);
}
public function show(Post $post): Response
{
return Inertia::render('Posts/Show', [
'post' => $post->load('user', 'comments.user'),
]);
}
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string',
]);
$post = Post::create([
...$validated,
'user_id' => $request->user()->id,
]);
return redirect()->route('posts.show', $post)
->with('success', 'Post créé avec succès.');
}
}
Page Vue 3
<script setup lang="ts">
import AppLayout from '@/Layouts/App.vue';
import { Link, router } from '@inertiajs/vue3';
import { ref } from 'vue';
interface Post {
id: number;
title: string;
content: string;
user: { name: string };
created_at: string;
}
const props = defineProps<{
posts: {
data: Post[];
meta: { current_page: number; last_page: number; total: number };
};
}>();
const search = ref('');
const filter = () => {
router.get(route('posts.index'), { search: search.value }, {
preserveState: true,
replace: true,
});
};
</script>
<template>
<AppLayout title="Posts">
<template #header>
<h1>Posts</h1>
</template>
<!-- Recherche -->
<input v-model="search" @input="filter" placeholder="Rechercher..." />
<!-- Liste -->
<div v-for="post in posts.data" :key="post.id">
<Link :href="route('posts.show', post.id)">
{{ post.title }}
</Link>
<span>{{ post.user.name }}</span>
</div>
<!-- Pagination -->
<div>
<Link
v-for="link in posts.meta.links"
:key="link.url"
:href="link.url"
:class="{ 'font-bold': link.active }"
v-html="link.label"
/>
</div>
</AppLayout>
</template>
Partial Reloads
// Controller
public function show(Post $post): Response
{
return Inertia::render('Posts/Show', [
'post' => $post,
'comments' => $post->comments, // Rechargé seulement si nécessaire
]);
}
<script setup>
import { router } from '@inertiajs/vue3';
// Recharger seulement les comments
router.reload({ only: ['comments'] });
</script>
Prefetching
<script setup>
import { Link } from '@inertiajs/vue3';
</script>
<template>
<!-- Prefetch au hover -->
<Link :href="route('posts.show', post.id)" prefetch>
{{ post.title }}
</Link>
<!-- Prefetch on intent (hover ou focus) -->
<Link :href="route('posts.show', post.id)" prefetch="intent">
{{ post.title }}
</Link>
</template>
Layouts partagés
// app/Http/Middleware/HandleInertiaRequests.php
public function share(Request $request): array
{
return [
'user' => $request->user() ? [
'id' => $request->user()->id,
'name' => $request->user()->name,
'email' => $request->user()->email,
] : null,
'flash' => [
'success' => fn () => $request->session()->get('success'),
'error' => fn () => $request->session()->get('error'),
],
];
}
SSR (Server-Side Rendering)
# Installer le SSR
php artisan inertia:middleware
// config/inertia.php
return [
'ssr' => [
'enabled' => true,
'url' => 'http://127.0.0.1:13714',
],
];
Bonnes pratiques
Inertia::render()côté controller, pas de retour JSON- Partial reloads pour les navigations partielles
- Layouts partagés via
HandleInertiaRequests - Props typées côté frontend (TypeScript)
- Prefetching pour les navigations prévisibles
- Progress bar —
router.on('start', () => NProgress.start()) - Preserve scroll —
preserveScroll: truequand nécessaire - Error handling —
router.onError()pour les erreurs globales
Validation
- Toutes les pages utilisent
Inertia::render() - Layouts partagés configurés
- Partial reloads utilisés quand pertinent
- Props typées en TypeScript
- SSR configuré si nécessaire