Passer au contenu principal

Qu’est-ce que Vue.js ?

Vue.js (ci-après Vue) est un framework JavaScript progressif pour construire des interfaces utilisateur. « Progressif » signifie que vous pouvez commencer petit et ajouter des fonctionnalités selon vos besoins ; il peut s’intégrer partiellement dans une page HTML existante ou servir à la construction de SPA à grande échelle. L’essence de Vue est la réactivité. Lorsque les données changent, le DOM est automatiquement mis à jour ; le développeur n’a donc pas à gérer manuellement « quand et quels éléments mettre à jour ».
Cette page présente la combinaison Vue 3 et Inertia v3. Le starter kit de Laravel 13 utilise cette configuration par défaut.

Options API et Composition API

Vue 3 propose deux styles d’écriture de composants : Options API et Composition API. Options API est le style traditionnel hérité de Vue 2. Vous définissez un composant avec un objet d’options : data, methods, computed, mounted, etc.
<!-- Exemple avec Options API -->
<script>
export default {
    data() {
        return { count: 0 }
    },
    methods: {
        increment() {
            this.count++
        }
    }
}
</script>

<template>
    <button @click="increment">{{ count }}</button>
</template>
Composition API est le nouveau style introduit dans Vue 3. Combiné à la syntaxe <script setup>, il permet une écriture plus concise. Il offre également une meilleure réutilisation logique et une excellente affinité avec TypeScript.
<!-- Exemple Composition API (<script setup>) -->
<script setup>
import { ref } from 'vue'

const count = ref(0)

function increment() {
    count.value++
}
</script>

<template>
    <button @click="increment">{{ count }}</button>
</template>
Dans les starter kits Inertia × Laravel, le style Composition API avec <script setup> est le standard. Tous les exemples de cette page sont écrits en <script setup>.

Position dans Laravel

Histoire

La relation entre Vue et Laravel est ancienne, remontant à Laravel 5.3 (2016), lorsque Vue a été adopté comme framework front-end par défaut. À l’époque, package.json incluait Vue, et un composant d’exemple resources/js/components/ExampleComponent.vue était fourni. Dans Laravel 6 (2019), le scaffold d’authentification a été extrait dans le paquet laravel/ui, et le scaffold Vue a également migré vers ce paquet. Aujourd’hui, le style principal consiste à choisir la configuration Inertia + Vue via un starter kit avec laravel new. Pour les utilisateurs de Laravel, Vue est le framework JS le plus familier, et les ressources d’apprentissage en français sont abondantes.

Le style principal actuel : Inertia × Vue

L’utilisation centrale de Vue dans Laravel aujourd’hui est Inertia × Vue. Inertia permet une architecture « monolithe moderne » où l’on peut passer directement des données du contrôleur Laravel aux composants Vue sans concevoir d’API.

Installation

Via un starter kit (recommandé)

Pour démarrer un nouveau projet, utiliser un starter kit est le moyen le plus simple.
laravel new my-app
En sélectionnant Vue dans l’invite interactive, tout ce qui suit est configuré automatiquement.
  • inertiajs/inertia-laravel (adaptateur côté serveur)
  • @inertiajs/vue3 (adaptateur côté client)
  • vue (Vue 3 lui-même)
  • @vitejs/plugin-vue (plugin Vite)
  • Middleware HandleInertiaRequests
  • Écrans d’authentification (connexion, inscription, etc.) déjà implémentés en Inertia + Vue

Installation manuelle

Pour ajouter à un projet existant, installez séparément les parties serveur et client.
# Côté serveur (PHP)
composer require inertiajs/inertia-laravel

# Côté client (JavaScript)
npm install @inertiajs/vue3 vue
npm install --save-dev @vitejs/plugin-vue
Ensuite, ajoutez le plugin Vue à vite.config.js.
import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
        vue({
            template: {
                transformAssetUrls: {
                    base: null,
                    includeAbsolute: false,
                },
            },
        }),
    ],
})
Démarrez l’application Inertia dans resources/js/app.js.
import { createApp, h } from 'vue'
import { createInertiaApp } from '@inertiajs/vue3'
import { resolvePageComponent } from 'laravel-vite-plugin/inertia-helpers'

createInertiaApp({
    resolve: (name) =>
        resolvePageComponent(
            `./pages/${name}.vue`,
            import.meta.glob('./pages/**/*.vue'),
        ),
    setup({ el, App, props, plugin }) {
        createApp({ render: () => h(App, props) })
            .use(plugin)
            .mount(el)
    },
})
Pour les détails de l’installation manuelle (configuration du template racine, enregistrement du middleware, etc.), consultez la documentation officielle d’Inertia.

Structure des répertoires

Dans les starter kits, les composants de page Vue sont placés dans le répertoire resources/js/pages/.
resources/js/
├── app.js             # Point de départ de l'application Inertia
├── bootstrap.js
├── components/        # Composants UI réutilisables
│   ├── NavBar.vue
│   └── ...
├── layouts/           # Composants de mise en page
│   ├── AppLayout.vue
│   └── AuthLayout.vue
└── pages/             # Composants de page Inertia (correspondant aux noms de contrôleurs)
    ├── Auth/
    │   ├── Login.vue
    │   └── Register.vue
    ├── Dashboard.vue
    └── Posts/
        ├── Index.vue
        ├── Create.vue
        └── Show.vue
Lorsque vous écrivez Inertia::render('Posts/Index', [...]), le composant correspondant est resources/js/pages/Posts/Index.vue.

Syntaxe des templates Vue

Voici les directives de template de base nécessaires pour lire et écrire le code d’un starter kit.

{{ }} — interpolation de variables

Utilisez les doubles accolades pour intégrer des valeurs ou expressions JavaScript dans le template.
<script setup>
const name = 'le monde'
const count = 3
</script>

<template>
    <p>Bonjour, {{ name }} !</p>
    <p>Le double vaut {{ count * 2 }}</p>
</template>

v-if — branchement conditionnel

<template>
    <p v-if="isLoggedIn">Bienvenue !</p>
    <p v-else-if="role === 'admin'">Connecté en tant qu'administrateur</p>
    <a v-else href="/login">Se connecter</a>
</template>
Équivalent à {#if} de Svelte ou à l’opérateur ternaire de React.

v-for — rendu de listes

<template>
    <ul>
        <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
    </ul>
</template>
Pour une mise à jour différentielle efficace, spécifiez toujours :key. Équivalent à Array.map() de React.

v-model — liaison bidirectionnelle

Avec v-model, vous pouvez synchroniser en bidirectionnel la valeur d’un élément de formulaire et une variable réactive.
<script setup>
import { ref } from 'vue'

const title = ref('')
const agreed = ref(false)
const role = ref('viewer')
</script>

<template>
    <!-- Champ texte -->
    <input v-model="title" type="text" />
    <p>Saisie en cours : {{ title }}</p>

    <!-- Case à cocher -->
    <input v-model="agreed" type="checkbox" />
    <p>Accord : {{ agreed }}</p>

    <!-- Liste déroulante -->
    <select v-model="role">
        <option value="viewer">Lecteur</option>
        <option value="editor">Éditeur</option>
        <option value="admin">Administrateur</option>
    </select>
</template>

: (v-bind) et @ (v-on)

  • :attr="value" — liaison d’une valeur dynamique à un attribut HTML (forme abrégée de v-bind:attr)
  • @event="handler" — enregistrement d’un écouteur d’événement (forme abrégée de v-on:event)
<template>
    <!-- Liaison d'attribut dynamique -->
    <img :src="imageUrl" :alt="imageAlt" />

    <!-- Gestionnaires d'événements -->
    <button @click="handleClick">Cliquer</button>
    <form @submit.prevent="handleSubmit">...</form>
</template>

Bases des composants de page

Les composants de page Inertia sont de simples composants Vue. Les données passées depuis les contrôleurs Laravel sont reçues comme props.

Contrôleur

// app/Http/Controllers/PostController.php
use Inertia\Inertia;
use App\Models\Post;

class PostController extends Controller
{
    public function index()
    {
        return Inertia::render('Posts/Index', [
            'posts' => Post::latest()->paginate(10),
        ]);
    }
}

Composant de page Vue

<!-- resources/js/pages/Posts/Index.vue -->
<script setup>
import { Link } from '@inertiajs/vue3'

defineProps({
    posts: Object,
})
</script>

<template>
    <div>
        <h1>Liste des publications</h1>
        <article v-for="post in posts.data" :key="post.id">
            <h2>
                <Link :href="`/posts/${post.id}`">{{ post.title }}</Link>
            </h2>
            <p>{{ post.created_at }}</p>
        </article>
    </div>
</template>
Il suffit de déclarer les props avec defineProps() pour utiliser dans le template les données passées par le contrôleur. Aucune API REST n’a besoin d’être définie.
Grâce au composant <Link> fourni par @inertiajs/vue3, les transitions de page se font via XHR, évitant un rechargement complet du navigateur.
<script setup>
import { Link } from '@inertiajs/vue3'
</script>

<template>
    <!-- Lien de base -->
    <Link href="/posts">Liste des publications</Link>

    <!-- Lien avec méthode POST (suppression, etc.) -->
    <Link href="/posts/1" method="delete" as="button" type="button">
        Supprimer
    </Link>

    <!-- Préchargement (récupération anticipée au survol) -->
    <Link href="/posts/1" preload>Voir la publication</Link>
</template>
Vous pouvez l’écrire comme une balise <a> classique, mais en coulisses, Inertia ne remplace que le composant de page, offrant une expérience proche d’une SPA.

Composant Form

Le composant <Form> fourni par @inertiajs/vue3 est le style recommandé pour la soumission de formulaires, utilisé dans les écrans d’authentification des starter kits. On spécifie action et method en props et on accède à errors et processing avec v-slot.

Utilisation de base

<script setup>
import { Form } from '@inertiajs/vue3'
</script>

<template>
    <Form action="/posts" method="post" class="flex flex-col gap-4" v-slot="{ errors, processing }">
        <div>
            <label for="title">Titre</label>
            <input id="title" name="title" type="text" required />
            <p v-if="errors.title" class="error">{{ errors.title }}</p>
        </div>

        <div>
            <label for="content">Contenu</label>
            <textarea id="content" name="content"></textarea>
            <p v-if="errors.content" class="error">{{ errors.content }}</p>
        </div>

        <button type="submit" :disabled="processing">
            {{ processing ? 'Envoi en cours...' : 'Publier' }}
        </button>
    </Form>
</template>
v-slot="{ errors, processing }" correspond à la syntaxe des slots scoped de Vue ; le composant Form calcule et transmet automatiquement ces valeurs. Pour les champs de formulaire, on utilise l’attribut natif HTML name au lieu de v-model, permettant le fonctionnement de la collecte standard des données du navigateur.

Modèle du starter kit

Le starter kit utilise Wayfinder pour gérer les routes sous forme d’objets. store.form() retourne un objet contenant action et method de l’objet route, et vous le passez à <Form> par spread avec v-bind.
<script setup lang="ts">
import { Form } from '@inertiajs/vue3'
import { store } from '@/routes/login'
</script>

<template>
    <Form
        v-bind="store.form()"
        :reset-on-success="['password']"
        v-slot="{ errors, processing }"
        class="flex flex-col gap-6"
    >
        <!-- Contenu du formulaire -->
    </Form>
</template>
Les champs spécifiés dans reset-on-success sont automatiquement réinitialisés lorsque la soumission réussit. Utilisez-le pour les champs que vous souhaitez vider après l’envoi, comme les champs de mot de passe.
Si vous n’utilisez pas Wayfinder, passer directement l’URL comme action="/login" fonctionne de la même manière.

Helper useForm

Pour le traitement des formulaires, utilisez le helper useForm de @inertiajs/vue3. La gestion de l’état, la soumission et l’affichage des erreurs de validation s’implémentent simplement.

Côté contrôleur

// app/Http/Controllers/PostController.php
class PostController extends Controller
{
    public function store(Request $request)
    {
        $validated = $request->validate([
            'title'   => ['required', 'string', 'max:255'],
            'content' => ['required', 'string'],
        ]);

        Post::create($validated + ['user_id' => auth()->id()]);

        return redirect()->route('posts.index')
            ->with('success', 'Publication créée.');
    }
}

Composant de formulaire Vue

<!-- resources/js/pages/Posts/Create.vue -->
<script setup>
import { useForm } from '@inertiajs/vue3'

const form = useForm({
    title: '',
    content: '',
})

function submit() {
    form.post('/posts')
}
</script>

<template>
    <form @submit.prevent="submit">
        <div>
            <label>Titre</label>
            <input v-model="form.title" type="text" />
            <p v-if="form.errors.title" class="error">{{ form.errors.title }}</p>
        </div>

        <div>
            <label>Contenu</label>
            <textarea v-model="form.content"></textarea>
            <p v-if="form.errors.content" class="error">{{ form.errors.content }}</p>
        </div>

        <button type="submit" :disabled="form.processing">
            {{ form.processing ? 'Envoi en cours...' : 'Publier' }}
        </button>
    </form>
</template>
Voici un résumé des principales propriétés retournées par useForm.
Propriété / méthodeDescription
form.dataObjet de données du formulaire
form.errorsErreurs de validation (accessibles par nom de champ)
form.processingtrue pendant l’envoi (à utiliser pour désactiver le bouton)
form.isDirtytrue si modifié par rapport à la valeur initiale
form.post(url)Envoi via une requête POST
form.put(url)Envoi via une requête PUT (mise à jour)
form.delete(url)Envoi via une requête DELETE
form.reset()Réinitialise le formulaire à sa valeur initiale
Lorsque des erreurs de validation sont retournées, useForm affiche les erreurs tout en conservant le contenu saisi. Combiné à v-model, cela offre une expérience de formulaire fluide.

Données partagées (Shared Data)

Les données communes à toutes les pages (informations utilisateur connectées, messages flash, etc.) sont définies via la méthode share() du middleware HandleInertiaRequests.
// app/Http/Middleware/HandleInertiaRequests.php
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()
                    ? $request->user()->only('id', 'name', 'email')
                    : null,
            ],
            'flash' => [
                'success' => $request->session()->get('success'),
                'error'   => $request->session()->get('error'),
            ],
        ]);
    }
}
Pour accéder aux données partagées depuis un composant Vue, utilisez usePage().
<script setup>
import { computed } from 'vue'
import { usePage } from '@inertiajs/vue3'

const page = usePage()

// Accès aux données partagées
const user = computed(() => page.props.auth.user)
const flash = computed(() => page.props.flash)
</script>

<template>
    <header>
        <span v-if="user">{{ user.name }}</span>
        <span v-else>Invité</span>
    </header>

    <div v-if="flash.success" class="alert-success">
        {{ flash.success }}
    </div>
</template>
Les données partagées sont incluses dans chaque requête ; il est donc recommandé de les limiter au strict nécessaire. En les enveloppant dans une évaluation paresseuse avec fn(), elles ne sont évaluées que lorsqu’elles sont réellement consultées.

Bases de la réactivité de Vue 3

Voici les API de réactivité de Vue 3 à connaître pour développer avec Inertia × Vue.

ref — valeur réactive primitive

<script setup>
import { ref } from 'vue'

const count = ref(0)
const isOpen = ref(false)

// Accès via .value (inutile dans le template)
count.value++
</script>

<template>
    <p>{{ count }}</p>
    <button @click="isOpen = !isOpen">Basculer</button>
</template>

computed — propriété calculée

<script setup>
import { ref, computed } from 'vue'

const posts = ref([])

const publishedPosts = computed(() =>
    posts.value.filter(post => post.published)
)
</script>

onMounted — traitement après montage

<script setup>
import { onMounted } from 'vue'

onMounted(() => {
    console.log('Le composant a été monté')
})
</script>

Résumé

Vue.js s’accorde bien avec Laravel, et sa force s’exprime tout particulièrement dans une configuration « monolithe moderne » via Inertia.
ÉlémentRôle
Contrôleur LaravelRoutage, récupération de données, validation
Inertia::render()Passe des données du contrôleur au composant Vue
Composant de page VueReçoit les props et rend l’UI
useFormGestion d’état, soumission, affichage des erreurs
Composant LinkTransition de page sans rechargement complet
usePage().propsAccès aux données partagées
Avec Inertia × Vue, vous profitez à la fois de la simplicité du back-end Laravel et de l’UI réactive de Vue. Créez un projet avec un starter kit et vous pourrez commencer à développer immédiatement, écrans d’authentification inclus.

Documentation officielle d'Inertia.js

Pour toutes les fonctionnalités d’Inertia v3, consultez la documentation officielle.
Dernière modification le 13 juillet 2026