Vai al contenuto principale

Cos’è Vue.js

Vue.js (di seguito “Vue”) è un framework JavaScript progressivo per costruire interfacce utente. “Progressivo” significa che puoi iniziare da parti piccole e aggiungere funzionalità quando servono: si adatta sia all’inserimento parziale in pagine HTML esistenti sia alla costruzione di SPA di grandi dimensioni. Il cuore di Vue è la reattività. Quando i dati cambiano, il DOM si aggiorna automaticamente, quindi non devi gestire manualmente “quando e quale elemento aggiornare”.
In questa pagina spieghiamo la combinazione di Vue 3 e Inertia v3. Lo starter kit di Laravel 13 usa questa configurazione per impostazione predefinita.

Options API e Composition API

Vue 3 offre due stili per scrivere i componenti: Options API e Composition API. Options API è lo stile tradizionale ereditato da Vue 2. Definisci il componente tramite un oggetto opzioni con data, methods, computed, mounted, ecc.
<!-- Esempio di Options API -->
<script>
export default {
    data() {
        return { count: 0 }
    },
    methods: {
        increment() {
            this.count++
        }
    }
}
</script>

<template>
    <button @click="increment">{{ count }}</button>
</template>
Composition API è lo stile introdotto in Vue 3. Combinandolo con la sintassi <script setup> puoi scrivere in modo più conciso. Ha una riusabilità della logica maggiore ed è particolarmente adatto a TypeScript.
<!-- Esempio di 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>
Gli starter kit di Inertia × Laravel usano come standard lo stile Composition API con <script setup>. Anche gli esempi in questa pagina sono tutti in <script setup>.

Posizione in Laravel

Storia

Il rapporto tra Vue e Laravel è di lunga data e inizia con l’adozione di Vue come framework frontend predefinito in Laravel 5.3 (2016). All’epoca Vue era incluso in package.json ed era fornito anche il componente d’esempio resources/js/components/ExampleComponent.vue. Con Laravel 6 (2019) lo scaffold di autenticazione è stato scorporato nel pacchetto laravel/ui e anche lo scaffold Vue è passato a quel pacchetto. Attualmente lo stile principale è scegliere la configurazione Inertia + Vue tramite gli starter kit di laravel new. Per gli utenti Laravel, Vue è il framework JS più familiare, con risorse di apprendimento in molte lingue.

Stile principale attuale: Inertia × Vue

Il modo principale di usare Vue in Laravel è Inertia × Vue. Inertia realizza l’architettura “monolite moderno” che permette di passare dati dai controller Laravel direttamente ai componenti Vue senza progettare un’API.

Setup

Tramite starter kit (consigliato)

Per iniziare un nuovo progetto il modo più semplice è usare lo starter kit.
laravel new my-app
Se scegli Vue nel prompt interattivo, viene tutto configurato automaticamente.
  • inertiajs/inertia-laravel (adapter lato server)
  • @inertiajs/vue3 (adapter lato client)
  • vue (Vue 3)
  • @vitejs/plugin-vue (plugin Vite)
  • Middleware HandleInertiaRequests
  • Schermate di autenticazione (login, registrazione, ecc.) già implementate con Inertia + Vue

Installazione manuale

Per aggiungerlo a un progetto esistente, installa separatamente lato server e lato client.
# Lato server (PHP)
composer require inertiajs/inertia-laravel

# Lato client (JavaScript)
npm install @inertiajs/vue3 vue
npm install --save-dev @vitejs/plugin-vue
Aggiungi poi il plugin Vue in 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,
                },
            },
        }),
    ],
})
Avvia l’app Inertia in 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)
    },
})
Per i dettagli dell’installazione manuale (configurazione del template root, registrazione dei middleware, ecc.) consulta la documentazione ufficiale di Inertia.

Struttura delle directory

Negli starter kit i componenti pagina Vue vanno nella directory resources/js/pages/.
resources/js/
├── app.js             # Entry point dell'app Inertia
├── bootstrap.js
├── components/        # Componenti UI riutilizzabili
│   ├── NavBar.vue
│   └── ...
├── layouts/           # Componenti di layout
│   ├── AppLayout.vue
│   └── AuthLayout.vue
└── pages/             # Componenti pagina Inertia (corrispondono ai nomi dei controller)
    ├── Auth/
    │   ├── Login.vue
    │   └── Register.vue
    ├── Dashboard.vue
    └── Posts/
        ├── Index.vue
        ├── Create.vue
        └── Show.vue
Scrivendo Inertia::render('Posts/Index', [...]), il componente corrispondente è resources/js/pages/Posts/Index.vue.

Sintassi dei template Vue

Ecco le direttive di template di base che servono per leggere e scrivere il codice degli starter kit.

{{ }} — espansione di variabili

Con le doppie parentesi graffe incorpori valori o espressioni JavaScript nel template.
<script setup>
const name = 'mondo'
const count = 3
</script>

<template>
    <p>Ciao, {{ name }}!</p>
    <p>Il doppio è {{ count * 2 }}</p>
</template>

v-if — condizionali

<template>
    <p v-if="isLoggedIn">Benvenuto!</p>
    <p v-else-if="role === 'admin'">Loggato come amministratore</p>
    <a v-else href="/login">Login</a>
</template>
Corrisponde a {#if} di Svelte o all’operatore ternario di React.

v-for — rendering di liste

<template>
    <ul>
        <li v-for="post in posts" :key="post.id">{{ post.title }}</li>
    </ul>
</template>
Specifica sempre :key per un aggiornamento differenziale efficiente. Corrisponde a Array.map() di React.

v-model — binding bidirezionale

Con v-model puoi sincronizzare bidirezionalmente il valore di un elemento form e una variabile reattiva.
<script setup>
import { ref } from 'vue'

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

<template>
    <!-- Input di testo -->
    <input v-model="title" type="text" />
    <p>In inserimento: {{ title }}</p>

    <!-- Checkbox -->
    <input v-model="agreed" type="checkbox" />
    <p>Accettato: {{ agreed }}</p>

    <!-- Select -->
    <select v-model="role">
        <option value="viewer">Lettore</option>
        <option value="editor">Editor</option>
        <option value="admin">Amministratore</option>
    </select>
</template>

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

  • :attr="value" — bind di un valore dinamico su un attributo HTML (forma abbreviata di v-bind:attr)
  • @event="handler" — registra un listener di evento (forma abbreviata di v-on:event)
<template>
    <!-- Bind dinamico di attributi -->
    <img :src="imageUrl" :alt="imageAlt" />

    <!-- Event handler -->
    <button @click="handleClick">Clicca</button>
    <form @submit.prevent="handleSubmit">...</form>
</template>

Le basi del componente pagina

I componenti pagina di Inertia sono normali componenti Vue. I dati passati dal controller Laravel arrivano come props.

Controller

// 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),
        ]);
    }
}

Componente pagina Vue

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

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

<template>
    <div>
        <h1>Elenco dei post</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>
Basta dichiarare le props con defineProps() per usare nel template i dati passati dal controller. Non serve definire un’API REST.
Usando il componente <Link> di @inertiajs/vue3, le transizioni avvengono via XHR ed eviti il full reload del browser.
<script setup>
import { Link } from '@inertiajs/vue3'
</script>

<template>
    <!-- Link di base -->
    <Link href="/posts">Elenco post</Link>

    <!-- Link con metodo POST (ad es. per l'eliminazione) -->
    <Link href="/posts/1" method="delete" as="button" type="button">
        Elimina
    </Link>

    <!-- Preload (fetch anticipato all'hover) -->
    <Link href="/posts/1" preload>Vedi il post</Link>
</template>
Si scrive come un normale tag <a>, ma dietro le quinte Inertia sostituisce solo il componente di pagina, dando una sensazione da SPA.

Componente Form

Il componente <Form> fornito da @inertiajs/vue3 è lo stile consigliato usato dagli starter kit per l’invio dei form. Specifichi action e method come props e accedi a errors e processing tramite v-slot.

Uso di 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">Titolo</label>
            <input id="title" name="title" type="text" required />
            <p v-if="errors.title" class="error">{{ errors.title }}</p>
        </div>

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

        <button type="submit" :disabled="processing">
            {{ processing ? 'Invio in corso...' : 'Pubblica' }}
        </button>
    </Form>
</template>
v-slot="{ errors, processing }" è la sintassi di scoped slot di Vue; il componente Form calcola e passa automaticamente questi valori. Ai campi si assegna l’attributo HTML nativo name invece di v-model, così funziona la raccolta standard dei dati del browser.

Pattern degli starter kit

Gli starter kit gestiscono le rotte come oggetti tramite Wayfinder. store.form() restituisce un oggetto contenente action e method dell’oggetto rotta e viene passato a <Form> con 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"
    >
        <!-- Contenuto del form -->
    </Form>
</template>
I campi specificati in reset-on-success vengono ripristinati automaticamente in caso di invio riuscito. Utile per campi come la password che vuoi svuotare dopo l’invio.
Se non usi Wayfinder puoi passare direttamente l’URL come action="/login" e funziona allo stesso modo.

Helper useForm

Per la gestione dei form usa l’helper useForm di @inertiajs/vue3. Puoi implementare in modo semplice gestione stato, invio ed errori di validazione.

Lato controller

// 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', 'Post creato.');
    }
}

Componente form 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>Titolo</label>
            <input v-model="form.title" type="text" />
            <p v-if="form.errors.title" class="error">{{ form.errors.title }}</p>
        </div>

        <div>
            <label>Contenuto</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 ? 'Invio in corso...' : 'Pubblica' }}
        </button>
    </form>
</template>
Ecco le principali proprietà restituite da useForm.
Proprietà / MetodoDescrizione
form.dataOggetto dati del form
form.errorsErrori di validazione (accesso per nome campo)
form.processingtrue durante l’invio (per disabilitare il pulsante)
form.isDirtytrue se ci sono modifiche rispetto ai valori iniziali
form.post(url)Invia con richiesta POST
form.put(url)Invia con richiesta PUT (update)
form.delete(url)Invia con richiesta DELETE
form.reset()Ripristina il form ai valori iniziali
Quando arrivano errori di validazione, useForm mantiene i contenuti inseriti mostrando gli errori. In combinazione con v-model offre un’esperienza di form senza interruzioni.

Dati condivisi (Shared Data)

I dati necessari a tutte le pagine (utente loggato, messaggi flash, ecc.) si definiscono nel metodo share() del 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'),
            ],
        ]);
    }
}
Per accedere ai dati condivisi da un componente Vue usa usePage().
<script setup>
import { computed } from 'vue'
import { usePage } from '@inertiajs/vue3'

const page = usePage()

// Accesso ai dati condivisi
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>Ospite</span>
    </header>

    <div v-if="flash.success" class="alert-success">
        {{ flash.success }}
    </div>
</template>
Poiché i dati condivisi sono inclusi in ogni richiesta, si consiglia di limitarli allo stretto necessario. Con valutazioni lazy tramite fn(), vengono valutati solo quando ci si accede davvero.

Basi della reattività di Vue 3

Ecco le API di reattività di Vue 3 essenziali per sviluppare con Inertia × Vue.

ref — valore reattivo primitivo

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

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

// Accesso tramite .value (non serve nel template)
count.value++
</script>

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

computed — proprietà calcolate

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

const posts = ref([])

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

onMounted — elaborazioni dopo il mount

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

onMounted(() => {
    console.log('Il componente è stato montato')
})
</script>

Conclusioni

Vue.js ha una grande affinità con Laravel e dà il meglio nell’architettura “monolite moderno” tramite Inertia.
ElementoRuolo
Controller LaravelRouting, recupero dati e validazione
Inertia::render()Passa i dati dal controller al componente Vue
Componente pagina VueRiceve le props e renderizza la UI
useFormGestione stato, invio ed errori del form
Componente LinkTransizioni di pagina senza full reload
usePage().propsAccesso ai dati condivisi
Con Inertia × Vue ottieni sia la semplicità del backend Laravel sia la UI reattiva di Vue. Creando il progetto tramite starter kit, puoi iniziare subito con schermate di autenticazione incluse.

Documentazione ufficiale di Inertia.js

Per tutte le funzionalità di Inertia v3 consulta la documentazione ufficiale.
Ultima modifica il 13 luglio 2026