Module 2 – Installation et premier projet
Niveau 5.2 – Laravel Inertia (React & Vue)
Objectif
À la fin de ce module vous aurez :
- Un projet Laravel avec Inertia installé côté serveur et côté client (React ou Vue).
- Une racine (root view) qui charge l’app et injecte les données de page.
- Une première page Inertia (composant React ou Vue) affichée via une route Laravel.
Nous détaillons chaque étape pour que vous puissiez reproduire la configuration sur une nouvelle app ou sur une app Laravel existante. Les deux stacks (React et Vue) sont traitées en parallèle.
Vue d’ensemble de l’installation
L’installation se fait en deux parties :
- Côté Laravel (PHP) : package
inertiajs/inertia-laravel, middleware, et une vue Blade qui sert de « racine » (template HTML unique chargé au premier coup, puis utilisé par Inertia pour injecter les réponses). - Côté client (JavaScript) : package
@inertiajs/reactou@inertiajs/vue3, configuration de Vite pour React ou Vue, et un point d’entrée (app.jsxouapp.js) qui initialise l’app Inertia et résout les composants de page.
Nous supposons que vous utilisez Vite (fourni par défaut avec Laravel depuis Laravel 9). Si vous avez encore Mix (Laravel Mix), la logique reste la même mais les chemins et la config diffèrent.
Étape 1 – Créer ou ouvrir un projet Laravel
Si vous partez de zéro :
composer create-project laravel/laravel mon-app-inertia
cd mon-app-inertia
Si vous avez déjà un projet Laravel, placez-vous à la racine du projet. Vérifiez que Vite est bien configuré : fichier vite.config.js à la racine et dans package.json les scripts "dev", "build", etc.
Étape 2 – Installer Inertia côté Laravel
composer require inertiajs/inertia-laravel
Cela installe le package officiel qui fournit :
- La façade
Inertiaet la méthodeInertia::render(). - Un middleware qui prépare la réponse Inertia (partage de données, format de réponse).
- Des directives Blade utiles pour la root view (voir plus bas).
Publier et enregistrer le middleware
php artisan inertia:middleware
Cette commande crée (ou met à jour) le middleware HandleInertiaRequests dans app/Http/Middleware/HandleInertiaRequests.php. Il doit être enregistré dans le groupe web pour que toutes les routes web passent par lui.
Laravel 11 (fichier bootstrap/app.php) :
->withMiddleware(function (Middleware $middleware) {
$middleware->web(append: [
\App\Http\Middleware\HandleInertiaRequests::class,
]);
})
Laravel 10 et avant (fichier app/Http/Kernel.php) : ajouter la classe dans le tableau $middlewareGroups['web'] :
protected $middlewareGroups = [
'web' => [
// ... autres middlewares
\App\Http\Middleware\HandleInertiaRequests::class,
],
];
Sans ce middleware, Laravel ne formatera pas correctement les réponses pour Inertia (pas de clé page, pas de format JSON attendu par le client).
Étape 3 – Créer la root view (template HTML racine)
Inertia a besoin d’une seule page HTML qui sera chargée au premier accès (ou à chaque refresh). Cette page contient une div dans laquelle Inertia injectera le contenu (ou les données pour l’hydratation).
Créez par exemple resources/views/app.blade.php :
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="csrf-token" content="{{ csrf_token() }}">
<title>{{ config('app.name', 'Laravel') }}</title>
<!-- Fonts, favicon, etc. si besoin -->
<!-- Vite : chargement des assets JS et CSS -->
@viteReactRefresh
@vite(['resources/js/app.jsx', 'resources/css/app.css'])
</head>
<body>
<div id="app" data-page="{{ json_encode($page) }}"></div>
@inertiaHead
</body>
</html>
Points importants :
<div id="app">: c’est le conteneur dans lequel React ou Vue montera l’application. L’attributdata-pagecontient les données de la page courante (composant + props) en JSON ; au premier chargement, le client Inertia lit ce JSON pour faire le rendu initial (évitant un flash de page blanche).@vite(['resources/js/app.jsx', ...]): adaptez selon votre stack. Pour React on charge souventapp.jsx(ouapp.tsx), pour Vue on chargeapp.js(voir plus bas).@inertiaHead: directive fournie par le package Inertia pour injecter des balises dans le<head>quand une page en demande (titres, meta). Utile pour le SEO.@viteReactRefresh: à utiliser uniquement si vous utilisez React (hot reload). Pour Vue seul, ne pas mettre cette ligne ou utiliser l’équivalent Vue si nécessaire.
Si vous utilisez Vue au lieu de React, la même root view peut ressembler à ceci (sans @viteReactRefresh si vous n’utilisez pas React) :
@vite(['resources/js/app.js', 'resources/css/app.css'])
et dans <body> toujours :
<div id="app" data-page="{{ json_encode($page) }}"></div>
@inertiaHead
La variable $page est fournie par le middleware HandleInertiaRequests : il construit un tableau avec le nom du composant et les props, que le client utilise pour le rendu.
Étape 4 – Côté client : installer React ou Vue + Inertia
Vous devez choisir React ou Vue. Nous détaillons les deux.
Option A – Stack React
Installation des dépendances npm :
npm install @inertiajs/react react react-dom
npm install -D @vitejs/plugin-react
Fichier vite.config.js (à la racine du projet) : activer le plugin React.
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.jsx'],
refresh: true,
}),
react(),
],
resolve: {
alias: {
'@': '/resources/js',
},
},
});
Si votre point d’entrée est app.tsx au lieu de app.jsx, remplacez resources/js/app.jsx par resources/js/app.tsx dans input et dans la root view.
Point d’entrée – resources/js/app.jsx :
import './bootstrap';
import '../css/app.css';
import { createInertiaApp } from '@inertiajs/react';
import { createRoot } from 'react-dom/client';
import React from 'react';
createInertiaApp({
resolve: (name) => {
const pages = import.meta.glob('./Pages/**/*.jsx');
const path = `./Pages/${name}.jsx`;
if (!pages[path]) {
throw new Error(`Page Inertia non trouvée: ${name}`);
}
return pages[path]();
},
setup({ el, App, props }) {
const root = createRoot(el);
root.render(<App {...props} />);
},
title: (title) => (title ? `${title} - ${import.meta.env.VITE_APP_NAME ?? 'App'}` : import.meta.env.VITE_APP_NAME ?? 'App'),
});
Explication :
resolve(name): Inertia appelle cette fonction avec le nom du composant (ex."Welcome"ou"Articles/Index"). Ici on charge dynamiquement le fichier correspondant :./Pages/Welcome.jsxou./Pages/Articles/Index.jsx.import.meta.glob('./Pages/**/*.jsx')donne un objet dont les clés sont les chemins ; on appelle la fonction pour ce chemin pour obtenir le module (et donc le composant).setup({ el, App, props }):elest l’élément DOM (la div#app),Appest le composant de page à afficher,propssont les props à lui passer. On utilise createRoot (React 18) pour rendre<App {...props} />dansel.title: optionnel ; permet de définir le titre du document selon ce que la page demande.
Première page – resources/js/Pages/Welcome.jsx :
import React from 'react';
export default function Welcome() {
return (
<div>
<h1>Bienvenue avec Laravel + Inertia + React</h1>
<p>Si vous voyez ce message, l’installation a réussi.</p>
</div>
);
}
Convention : les composants de page vivent sous resources/js/Pages/. Le nom passé à Inertia::render('Welcome') correspond au fichier Pages/Welcome.jsx (sans extension).
Option B – Stack Vue
Installation des dépendances npm :
npm install @inertiajs/vue3 vue
npm install -D @vitejs/plugin-vue
Fichier vite.config.js :
import laravel from 'laravel-vite-plugin';
import vue from '@vitejs/plugin-vue';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
laravel({
input: ['resources/css/app.css', 'resources/js/app.js'],
refresh: true,
}),
vue(),
],
resolve: {
alias: {
'@': '/resources/js',
},
},
});
Point d’entrée – resources/js/app.js :
import './bootstrap';
import '../css/app.css';
import { createApp } from 'vue';
import { createInertiaApp } from '@inertiajs/vue3';
createInertiaApp({
resolve: (name) => {
const pages = import.meta.glob('./Pages/**/*.vue');
const path = `./Pages/${name}.vue`;
if (!pages[path]) {
throw new Error(`Page Inertia non trouvée: ${name}`);
}
return pages[path]();
},
setup({ el, App, props }) {
createApp(App, props).mount(el);
},
title: (title) => (title ? `${title} - ${import.meta.env.VITE_APP_NAME ?? 'App'}` : import.meta.env.VITE_APP_NAME ?? 'App'),
});
Première page – resources/js/Pages/Welcome.vue :
<template>
<div>
<h1>Bienvenue avec Laravel + Inertia + Vue</h1>
<p>Si vous voyez ce message, l’installation a réussi.</p>
</div>
</template>
<script setup>
</script>
Même idée : Inertia::render('Welcome') chargera Pages/Welcome.vue.
Étape 5 – Route Laravel et contrôleur
Il reste à faire en sorte que la route / (ou une autre) renvoie cette page Inertia.
Option simple – closure dans routes/web.php :
use Inertia\Inertia;
Route::get('/', function () {
return Inertia::render('Welcome');
});
Option avec contrôleur (pour les projets structurés) :
php artisan make:controller HomeController
// app/Http/Controllers/HomeController.php
namespace App\Http\Controllers;
use Inertia\Inertia;
class HomeController extends Controller
{
public function __invoke()
{
return Inertia::render('Welcome');
}
}
// routes/web.php
use App\Http\Controllers\HomeController;
Route::get('/', HomeController::class);
Important : la root view Blade (ex. app.blade.php) doit être celle utilisée par défaut pour les réponses Inertia. Le middleware HandleInertiaRequests s’occupe de fournir la variable $page à la vue. Il faut que votre application utilise bien cette vue comme « racine ». Avec le package officiel, c’est en général configuré automatiquement : quand vous faites Inertia::render(), Laravel utilise la vue racine configurée (souvent app.blade.php). Si vous avez personnalisé le nom de la vue racine, vérifiez la config ou le middleware.
Pour vérifier le nom de la root view, ouvrez app/Http/Middleware/HandleInertiaRequests.php et regardez la méthode rootView (souvent return 'app' pour resources/views/app.blade.php).
Étape 6 – Lancer l’application
- Démarrer Vite (en dev) :
npm run dev - Démarrer Laravel (autre terminal) :
php artisan serve - Ouvrir http://localhost:8000 dans le navigateur.
Vous devez voir le titre « Bienvenue avec Laravel + Inertia + React » (ou Vue) sans erreur console. Si vous voyez une page blanche ou une erreur, vérifiez :
- que le middleware HandleInertiaRequests est bien enregistré dans le groupe
web; - que la root view contient bien
<div id="app" data-page="{{ json_encode($page) }}"></div>et charge le bonapp.jsx/app.js; - que le fichier
Pages/Welcome.jsx(ouWelcome.vue) existe et exporte bien un composant par défaut.
Exemple avec des props (pour aller plus loin)
Pour vérifier que les props passent bien de Laravel au composant, modifions la route pour envoyer une donnée simple.
Laravel – routes/web.php :
Route::get('/', function () {
return Inertia::render('Welcome', [
'message' => 'Donnée envoyée depuis Laravel',
'timestamp' => now()->toDateTimeString(),
]);
});
React – resources/js/Pages/Welcome.jsx :
import React from 'react';
export default function Welcome({ message, timestamp }) {
return (
<div>
<h1>Bienvenue avec Laravel + Inertia + React</h1>
<p>{message}</p>
<p><small>Serveur : {timestamp}</small></p>
</div>
);
}
Vue – resources/js/Pages/Welcome.vue :
<template>
<div>
<h1>Bienvenue avec Laravel + Inertia + Vue</h1>
<p>{{ message }}</p>
<p><small>Serveur : {{ timestamp }}</small></p>
</div>
</template>
<script setup>
defineProps({
message: String,
timestamp: String,
});
</script>
En rechargeant la page, vous devez voir le message et l’horodatage venant du serveur. Cela confirme que le flux Laravel → Inertia → React/Vue fonctionne.
À retenir
- Côté Laravel :
composer require inertiajs/inertia-laravel, middleware HandleInertiaRequests dans le groupeweb, et une root view (ex.app.blade.php) avec<div id="app" data-page="{{ json_encode($page) }}"></div>et le chargement Vite. - Côté client : @inertiajs/react (ou @inertiajs/vue3) + React ou Vue, createInertiaApp avec resolve (chargement des composants sous
Pages/) et setup (montage React ou Vue). - Première page : créer
Pages/Welcome.jsx(React) ouPages/Welcome.vue(Vue), et une route qui renvoieInertia::render('Welcome')(avec ou sans props). - Toujours lancer
npm run deven développement pour que Vite compile et serve les assets.
Dans le prochain module, nous verrons comment structurer plusieurs pages, passer des props depuis les contrôleurs et organiser les routes.