Laravel 11 min di lettura

Laravel e Livewire: interfacce senza SPA

Quando il lavoro vero sta in form, filtri, permessi e processi, Livewire permette di restare dentro Laravel senza mettere in piedi un frontend separato.

Indice degli argomenti Il problema non è JavaScript

Succede spesso: prima ancora di parlare di flussi, permessi e vincoli, si comincia a discutere di stack.

La scena è abbastanza riconoscibile: si parte da Laravel, poi qualcuno propone React. Poi qualcuno se ne salta fuori con WordPress. Perché in fondo “sono solo schermate e campi”. Ecco: quando un gestionale con permessi, stati, documenti e flussi di approvazione diventa “solo schermate e campi”, di solito conviene fermarsi un attimo.

WordPress lo uso, lo conosco e lo difendo quando è la risposta giusta. Ma non deve diventare il coltellino svizzero con cui proviamo ad aprire anche le porte blindate.

Poi, se si decide di restare su Laravel, parte un altro cinema: frontend separato, Inertia, TypeScript, stato globale, client HTTP, validazioni duplicate, component library, gestione degli errori, loading state, toast, modal, dropdown, hydration, routing.

E magari il progetto deve mostrare a video alcuni form e raccogliere lead.

Per carità: React, Vue, Angular e le SPA hanno il loro posto. In Encodia li usiamo quando servono davvero. Il punto è non portarli dentro ogni progetto Laravel per abitudine, solo perché oggi sembra strano scrivere interfacce senza un grosso frontend JavaScript.

Per molti back office, portali clienti e gestionali, in Encodia partiamo spesso da qui: Laravel + Livewire.

Non perché Livewire faccia sparire JavaScript. Non lo fa. E nemmeno perché “così facciamo prima”, che da sola è una motivazione fragile.

Lo usiamo quando il lavoro vero sta in form, tabelle, filtri, permessi e flussi operativi, e vogliamo tenerlo vicino al codice Laravel che già governa il resto dell’applicazione.

Questo articolo non è un tutorial. È il ragionamento che facciamo spesso prima di scegliere come costruire un’applicazione Laravel che dovrà essere usata, modificata e mantenuta per anni.

Il problema non è JavaScript

JavaScript non è il nemico. Il browser vive di JavaScript e qualunque interfaccia seria ne usa almeno un po’.

Il punto è capire quanta logica deve finire nel browser.

Quando costruisci una SPA, spesso devi duplicare molte responsabilità:

  • il backend espone API;
  • il frontend ricostruisce il modello dati;
  • le validazioni devono parlare la stessa lingua da due lati diversi;
  • autorizzazioni ed errori vanno trasformati in stati UI;
  • la navigazione ha regole proprie;
  • i form diventano piccoli sistemi;
  • ogni modifica attraversa due posti diversi prima di arrivare in produzione.

Se il progetto lo richiede, va benissimo. Un prodotto SaaS con frontend separato, un’applicazione molto interattiva, un’esperienza realtime o un’interfaccia pubblica complessa possono meritare quella separazione.

Ma un portale clienti, un back office, un CRM, un gestionale operativo, un’area riservata, un sistema di approvazione documenti o una dashboard interna spesso hanno un’esigenza più semplice: uscire bene, farsi usare senza attrito e non diventare un problema a ogni modifica.

Qui Livewire diventa interessante.

Livewire riporta l’interfaccia dentro Laravel

Livewire fa una cosa abbastanza precisa: ti permette di scrivere componenti interattivi usando PHP e Blade. L’utente cambia un filtro, invia un form, clicca un’azione; Livewire parla con Laravel, aggiorna il componente e la pagina non viene ricaricata da capo.

La parte interessante, per me, non è la magia del componente che si aggiorna. È dove restano le responsabilità.

Con Livewire il backend non diventa un fornitore cieco di JSON. Resta l’applicazione.

Le regole di business restano nel backend. Le policy Laravel continuano a proteggere le azioni. La validazione sta vicino ai dati. I job finiscono in coda. Gli eventi restano eventi. I test possono controllare il comportamento senza dover aprire sempre un browser.

Un componente Livewire, nella sua forma più semplice, è quasi banale.

Disclaimer: non badare troppo al codice, lo snippet l’ho fatto generare da Pirillo™.

app/Livewire/Customers/CustomerIndex.php
namespace App\Livewire\Customers;
use App\Models\Customer;
use Illuminate\Contracts\View\View;
use Livewire\Component;
use Livewire\WithPagination;
class CustomerIndex extends Component
{
use WithPagination;
public string $search = '';
public string $status = 'active';
public function updatedSearch(): void
{
$this->resetPage();
}
public function archive(Customer $customer): void
{
$this->authorize('archive', $customer);
$customer->archive();
}
public function render(): View
{
return view('livewire.customers.index', [
'customers' => Customer::query()
->where('status', $this->status)
->when($this->search !== '', fn ($query) => $query->where('name', 'like', "%{$this->search}%"))
->latest()
->paginate(25),
]);
}
}

E la vista resta Blade:

resources/views/livewire/customers/index.blade.php
<div>
<div class="flex gap-3">
<input
type="search"
wire:model.live.debounce.300ms="search"
placeholder="Cerca cliente"
class="rounded-md border px-3 py-2"
>
<select wire:model.live="status" class="rounded-md border px-3 py-2">
<option value="active">Attivi</option>
<option value="archived">Archiviati</option>
</select>
</div>
<table class="mt-6 w-full">
@foreach ($customers as $customer)
<tr wire:key="customer-{{ $customer->id }}">
<td>{{ $customer->name }}</td>
<td class="text-right">
<button
type="button"
wire:click="archive({{ $customer->id }})"
wire:confirm="Archiviare questo cliente?"
>
Archivia
</button>
</td>
</tr>
@endforeach
</table>
{{ $customers->links() }}
</div>

Non c’è un controller API da inventare solo per questo filtro. Non c’è uno store client-side da sincronizzare. Non c’è una seconda validazione da tenere allineata. Non c’è un frontend separato che deve sapere troppe cose del dominio.

C’è un componente, con stato, azioni e vista.

Sembra poco sofisticato solo se confondiamo la sofisticazione con la quantità di strati.

Perché lo usiamo in Encodia

In Encodia Livewire ci interessa soprattutto nei progetti pieni di schermate operative: tante azioni piccole, tanti permessi, tanti stati, tante modifiche richieste dopo il rilascio.

Lo usiamo quando dobbiamo costruire:

  • back office su misura;
  • portali clienti;
  • gestionali verticali;
  • flussi di approvazione;
  • aree riservate con permessi;
  • dashboard operative;
  • form lunghi e condizionali;
  • tabelle con filtri, ordinamenti e paginazione;
  • caricamento e revisione di documenti;
  • interfacce amministrative che cambiano nel tempo.

In questi casi il frontend separato non è sempre un vantaggio. A volte è solo un altro posto in cui ricordarsi di cambiare la stessa regola.

Livewire si appoggia a Laravel invece di aggirarlo. Durante lo sviluppo questa differenza si sente subito.

Se un’azione richiede autorizzazione, usi le policy.

Se un form va validato, usi le regole Laravel.

Se un’operazione è lenta, la mandi in coda.

Se devi inviare una notifica, usi il sistema di notifiche.

Se vuoi testare un comportamento, puoi farlo vicino al codice PHP che lo governa:

tests/Feature/Livewire/CustomerIndexTest.php
use App\Livewire\Customers\CustomerIndex;
use App\Models\Customer;
use Livewire\Livewire;
it('filtra i clienti per nome', function () {
Customer::factory()->create(['name' => 'Rossi S.p.A.']);
Customer::factory()->create(['name' => 'Bianchi S.r.l.']);
Livewire::test(CustomerIndex::class)
->set('search', 'Rossi')
->assertSee('Rossi S.p.A.')
->assertDontSee('Bianchi S.r.l.');
});

Questa è una differenza pratica, non ideologica.

Meno colla significa meno punti in cui qualcosa può rompersi. Meno duplicazione significa meno costo a ogni modifica. Meno distanza tra interfaccia e dominio significa meno traduzioni mentali quando il cliente, dopo sei mesi, chiede una variazione che sembra piccola ma tocca mezzo flusso operativo.

Dove entra in gioco Alpine

Livewire e Alpine.js non fanno lo stesso mestiere.

Livewire sta bene dove c’è stato applicativo: dati, azioni, validazione, salvataggi, autorizzazioni, regole di dominio.

Alpine sta bene dove c’è stato locale: un menu aperto, un pannello espanso, una tab temporanea, un tooltip, una piccola interazione che non deve arrivare al server.

La stessa documentazione di installazione di Livewire spiega che Alpine viene caricato insieme a Livewire, salvo configurazioni manuali più specifiche. Questo è comodo, ma non significa che ogni cosa debba diventare Alpine o Livewire.

Il criterio che usiamo è abbastanza netto:

  • se lo stato cambia solo la UI, Alpine;
  • se lo stato cambia il dominio o deve essere validato, Livewire;
  • se l’interfaccia diventa un prodotto frontend autonomo, valutiamo altro.

Questa divisione evita due errori opposti: chiamare il server per aprire un dropdown, oppure infilare logica di business nel browser perché “tanto funziona”.

Dove entra in gioco Tailwind

Tailwind CSS non è il motivo per scegliere Livewire. È il modo in cui spesso costruiamo interfacce di lavoro senza portarci dietro un tema generico.

In un’applicazione aziendale, la UI deve essere prevedibile. Bottoni, tabelle, form, stati vuoti, messaggi di errore, badge, filtri e navigazione devono avere un linguaggio comune.

Tailwind aiuta perché porta il design vicino al markup e rende naturale costruire piccoli componenti Blade riutilizzabili:

resources/views/components/button.blade.php
<button
{{ $attributes->class([
'inline-flex items-center rounded-md px-3 py-2 text-sm font-semibold transition',
'bg-neutral-950 text-white hover:bg-neutral-800' => $variant === 'primary',
'border border-neutral-300 text-neutral-900 hover:bg-neutral-50' => $variant === 'secondary',
]) }}
>
{{ $slot }}
</button>

Qui il punto non è “usare classi utility perché sono moderne”. Il punto è evitare che ogni schermata sembri uscita da una decisione diversa.

Un gestionale non deve sembrare una landing page. Deve essere chiaro, denso il giusto, leggibile, veloce da usare e difficile da rompere.

Performance: non magia, buon senso

Livewire non rende automaticamente veloce un’applicazione. Nessuno strumento serio lo fa.

Ogni interazione Livewire passa dal server. Questo è il suo modello, non un dettaglio. Se lo usi male, puoi creare componenti rumorosi, query inutili, aggiornamenti troppo frequenti e interfacce che sembrano leggere ma fanno lavorare troppo il backend.

In Laravel, però, molte risposte sono già lì:

  • query pensate bene;
  • paginazione;
  • eager loading;
  • cache dove serve;
  • code per lavori pesanti;
  • validazione mirata;
  • componenti piccoli;
  • aggiornamenti differiti quando non serve il realtime;
  • lazy loading per blocchi costosi.

Livewire non sostituisce queste scelte. Le rende più vicine alla UI.

In pratica, noi cerchiamo di evitare componenti onnivori. Un componente Livewire dovrebbe avere una responsabilità chiara. Se dentro ci finiscono dieci flussi diversi, non è Livewire il problema: è progettazione pigra.

Sicurezza: il browser non diventa affidabile

Un vantaggio di Livewire è che molti sviluppatori Laravel si sentono subito a casa. Ma questa familiarità non deve diventare superficialità.

Il fatto che un’azione sia scritta in PHP non significa che sia automaticamente sicura. Ogni input resta input. Ogni azione sensibile deve passare da autorizzazione. Ogni parametro che arriva dal client va trattato per quello che è: qualcosa che l’utente può manipolare.

Il punto, però, è che con Livewire usi le stesse protezioni che useresti comunque in Laravel:

  • authorize() dentro le azioni;
  • policy per le regole di accesso;
  • validazione server-side;
  • middleware;
  • sessione e autenticazione;
  • CSRF;
  • log ed eventi;
  • test feature.

Questo è il motivo per cui lo trovo adatto a tanti progetti aziendali. Non perché semplifichi la sicurezza, ma perché evita di spargerla in più strati solo per tenere in piedi l’interfaccia.

Quando Livewire non è la scelta giusta

Dire che usiamo Livewire in Encodia non significa dire che lo useremmo sempre.

Non lo sceglierei come prima opzione per:

  • editor collaborativi in tempo reale;
  • interfacce offline-first;
  • applicazioni con stato client-side molto complesso;
  • dashboard con grafica altamente interattiva e aggiornamenti continui;
  • esperienze pubbliche in cui il frontend è il prodotto;
  • app mobile o desktop costruite sopra API condivise;
  • team frontend autonomi che devono lavorare separati dal backend.

In questi casi una SPA, Inertia, React, Vue, Angular o un’architettura API-first possono essere la strada migliore.

Il punto non è difendere Livewire. Il punto è non pagare il costo di un’architettura separata quando al progetto non serve davvero.

Filament e Flux

Negli ultimi anni, intorno a Livewire si è formato anche un ecosistema che nei progetti reali pesa.

Filament ha dimostrato bene una cosa: con Laravel e Livewire si possono costruire pannelli amministrativi solidi in tempi ragionevoli. Non è la risposta a ogni back office, ma quando il modello del progetto ci entra bene fa risparmiare molto tempo senza rinunciare a una base seria.

Flux UI è il sistema di componenti collegato al mondo Livewire e oggi compare anche nello starter kit Livewire ufficiale di Laravel. Questo dice una cosa semplice: Livewire non è più la scorciatoia laterale per chi vuole evitare JavaScript, ma una strada normale dentro l’ecosistema Laravel.

Questo non significa che bisogna installare tutto. In Encodia preferiamo partire dal progetto, non dal catalogo dei pacchetti.

Se Filament riduce tempo e rischio, lo valutiamo. Se serve un’interfaccia su misura, costruiamo componenti nostri. Se Flux accelera senza incastrarci, bene. Se introduce un vincolo non necessario, resta fuori.

La domanda resta sempre la stessa: fra un anno sarà ancora facile metterci mano?

Lo stack vero è Laravel

Quando si parla di stack, è facile fare l’elenco: Laravel, Livewire, Alpine, Tailwind, magari Filament, Redis, Meilisearch, Horizon, Forge, Docker, CI/CD.

La lista però dice poco.

La parte importante è capire chi fa cosa:

  • Laravel tiene insieme dominio, sicurezza, dati e processi;
  • Livewire rende interattiva la UI senza duplicare l’applicazione;
  • Alpine gestisce micro-interazioni locali;
  • Tailwind tiene coerente il linguaggio visivo;
  • i test proteggono i comportamenti che contano;
  • la pipeline di deploy rende il rilascio ripetibile;
  • il monitoraggio dice cosa succede dopo il lancio.

Questa è la parte che al cliente interessa anche se non usa queste parole.

Vuole sapere che il portale non diventerà ingestibile. Che una modifica non richiederà di riscrivere mezzo frontend. Che i permessi non saranno un insieme di if sparsi. Che i dati non finiranno in un limbo tra API e stato client. Che fra sei mesi qualcuno potrà aprire il progetto e capirci qualcosa.

Laravel e Livewire, usati bene, aiutano proprio qui.

Non è meno moderno. È meno dispersivo

C’è un pregiudizio ricorrente: se non hai un frontend JavaScript importante, allora stai facendo qualcosa di vecchio.

È una lettura pigra.

Moderno non significa spostare tutto nel browser. Significa scegliere confini chiari, pacchetti mantenuti, codice testabile, deploy ripetibili e modifiche che non costano ogni volta una settimana.

Per alcuni progetti questo porta a una SPA. Per altri porta ad Astro. Per altri a WordPress fatto con criterio. Per molti progetti Laravel aziendali, porta a Livewire.

La tecnologia giusta non è quella che fa più scena nella presentazione iniziale. È quella che dopo il lancio puoi ancora aprire, capire e modificare senza trattenere il fiato.

È per questo che in Encodia usiamo Livewire.

Non per evitare lavoro tecnico. Per evitare lavoro tecnico che non serve.

FAQ

Domande su Laravel e Livewire

Livewire sostituisce React, Vue o Angular?

No. Livewire non rimpiazza React, Vue o Angular. È comodo quando l’applicazione è Laravel e l’interfaccia serve soprattutto a gestire form, tabelle, permessi e flussi operativi. Se il frontend ha una vita propria, una SPA o Inertia possono essere la strada migliore.

Livewire va bene per progetti aziendali complessi?

Sì, se il progetto viene progettato bene. Livewire non elimina architettura, test, validazione, autorizzazioni e modellazione del dominio. Evita però di duplicare troppa logica tra API e frontend quando il centro del progetto è già Laravel.

Che ruolo ha Alpine.js con Livewire?

Alpine è utile per micro-interazioni locali: menu, dropdown, pannelli, stati visuali che non devono arrivare al server. Livewire gestisce invece stato applicativo, validazione, persistenza e azioni collegate al dominio.

Quando non useresti Livewire?

Non lo sceglierei come prima opzione per editor collaborativi in tempo reale, applicazioni offline-first, interfacce molto grafiche, canvas complessi o frontend che devono vivere come prodotto separato dal backend.