Laravel Inertia Vue3js
Dans le développement web, on distingue plusieurs architectures de site web :
Les applications monolithiques, le front et le back sont contenus dans la même application. Typiquement, laravel + blade.
Laravel génère des pages html à la demande et s'appuie sur le moteur de templatage blade.
A chaque demande du client (request), le serveur renvoie (response) le contenu (la data) et le contenant (html/css).
Les applications front en javascript (react, vue js...). L'application contient tout le contenant et les logiques d'appel au back.
Le back est une api. A chaque demande du client (le front), on appelle une route d'api (endpoint), ex https://application.test/api/books.
Le serveur ne va renvoyer que les données sous formatées en json.
Dans l'écosystème Laravel, nous avons la possibilité d'utiliser la bibliothèque Inertia js, qui va faire le liant entre le back et le front.
Le back et le front seront dans la même application, mais le front sera une application embarquée dans laravel en react ou vue js ou svelte.
De la même manière que le mode application Front qui fait appel à une api, Inertia, grâce à ses helpers, va nous permettre de passer beaucoup plus de données et de conserver des états. Comme par exemple, les routes de laravel, ou des objets useForm, très utiles pour la gestion des formulaires.
On peut installer inertia manuellement, ou utiliser les starter kits de laravel.
Les starters kit de laravel
https://laravel.com/starter-kits
Laravel nous met à disposition 3 nouveaux starter kit.
Laravel / react (avec inertia)
Laravel / vuejs (avec inertia)
Laravel / livewire (php avec une surcouche javascript)
Il n'y a pas de nouveau starter kit pour blade, mais on peut toujours utiliser laravel/breeze
https://laravel.com/docs/10.x/starter-kits
Examinons plus en détail l'installation de laravel avec vuejs
Pour bénéficier du choix dans l'installation, il faut installer l'application laravel
composer global require laravel/installer
ensuite il suffit de saisir la commande
laravel new nom-de-votre-projet

Laravel nous demande le type de stack que nous souhaitons installer

puis le type d'authentification, le plus simple est de sélectionner le mode intégré de laravel

ensuite le framework pour les tests

enfin, si l'on souhaite utiliser le package "boost" pour l'IA

Finalement, laravel va installer toutes les dépendances php
Vu que nous utilisons un starter kit, certaines pages sont déjà présentes, comme toute la gestion de l'authentification (login, register, lostpassword) et la gestion de son profil. Ces pages sont regroupées dans le dossier resources/js

On remarque à la racine deux fichiers particuliers, app.ts et ssr.ts.
app.ts va englober toute notre application front
ssr.ts va faire de même mais conserver cette application sur le serveur afin de pouvoir être référencée correctement par les moteurs de recherche.
Voici le contenu du fichier app.ts

Il contient le noyau d'inertia, et l'initialisation de l'application.
Une fois que notre application sera "buildée", elle sera automatiquent "bindée" dans le fichier resources/views/app.blade.php grâce aux directives blade, @inertiaHead et @inertia, ainsi inertia fait le lien entre le front et le back.

Coté back on conserve le routeur web laravel
use App\Http\Controllers\ContactController;
Route::get('/contact', [ContactController::class, 'index'])->name('contact.index');
Route::post('/contact', [ContactController::class, 'store'])->name('contact.store');
Ziggy
Jusqu'à récemment, les routes pouvaient être récupérées coté front, grâce à l'helper route et avec comme paramètre la route nommée.
Ce principe est très efficace, car en cas de changement d'url, la route nommée ne change pas et laravel retrouvera l'url.
Les routes pouvaient être récupérées par le front car elles étaient toutes envoyées au front grâce la bibliothèque ziggy et le middleware HandleInertiaRequest
Ce middleware permet entre-autre via la méthode share de partager des informations entre le back et le front, à chaque request
public function share(Request $request): array
{
try {
return [
...parent::share($request),
'name' => Inertia::once(static fn() => config('app.name')),
'auth' => [
'user' => $request->user('web')?->only('id', 'name', 'firstname', 'email', 'role', 'fullName'),
],
'ziggy' => [
...(new Ziggy)->toArray(),
'location' => $request->url(),
],
'env' => Inertia::once(static fn() => config('app.env')),
'url' => Inertia::once(static fn() => config('app.url')),
...
];
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
Log::error($e->getMessage(), $e->getCode());
}
return [];
}
il faut modifier le fichier resources/js/app.ts, afin d'importer ziggy
import { ZiggyVue } from 'ziggy-js';
...
.use(ZiggyVue)
Par exemple je veux créer un bouton qui pointe sur la page contact
<script setup lang="ts">
import { Link } from '@inertiajs/vue3';
</script>
<template>
<main>
<nav class="flex items-center justify-center gap-4">
<Link :href="route('contact.index')">{{
Contact-us
}}</Link>
</div>
</nav>
</main>
</template>
wayfinder
A présent laravel utilise le package laravel/wayfinder
https://github.com/laravel/wayfinder
"Laravel Wayfinder assure une transition fluide entre votre backend Laravel et votre frontend TypeScript. Il génère automatiquement des fonctions TypeScript entièrement typées et importables pour vos contrôleurs et routes, vous permettant ainsi d'appeler vos points de terminaison Laravel directement dans votre code client, comme n'importe quelle autre fonction. Fini les URL codées en dur, les paramètres de route à deviner et la synchronisation manuelle des modifications du backend."
A chaque création de routes dans le fichier routes/web, wayfinder va générer automatiquement, des fichiers typescript, contenant des informations de la route créée dans le dossier resources/js/routes
Comme par exemple pour les routes de contact
resources/js/routes/contact/index.ts
A présent le même exemple que plus haut mais avec wayfinder
<script setup lang="ts">
import { Link } from '@inertiajs/vue3';
// import des routes pour contact
import contact from '@/routes/contact';
</script>
<template>
<main>
<nav class="flex items-center justify-center gap-4">
<Link :href="contact.index()">{{
Contact-us
}}</Link>
</div>
</nav>
</main>
</template>
Dans cet exemple j'ai importé toutes les routes présentes pour contact, contact.index et contact.store dans l'objet contact.
On peut n'importer qu'une seule route, comme par exemple dans le formulaire de soumission de la page contact, je n'ai mis qu'un extrait de code avec un seul champ
<script setup lang="ts">
import InputError from '@/components/InputError.vue';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Spinner } from '@/components/ui/spinner';
import { Textarea } from '@/components/ui/textarea';
import AuthBase from '@/layouts/AuthLayout.vue';
// import de la route de soumission en post
import { store } from '@/routes/contact';
import { Form } from '@inertiajs/vue3';
</script>
<template>
<AuthBase>
<Form
v-bind="store.form()" <!-- utilisation la méthode store sur notre formulaire -->
v-slot="{ errors, processing }"
class="flex flex-col gap-6"
resetOnSuccess
>
<div class="grid gap-6">
<div class="grid gap-2">
<Label for="message">Message</Label>
<Textarea
id="message"
required
name="message"
placeholder="Message"
/>
<InputError :message="errors.message" />
</div>
<Button
type="submit"
class="mt-2 w-full"
tabindex="6"
:disabled="processing"
data-test="register-user-button"
>
<Spinner v-if="processing" />
Send
</Button>
</div>
</Form>
</AuthBase>
</template>
Le 11 décembre 2025
Temps de lecture : 15 min
