Livewire 4 est sorti en janvier 2026 avec un cycle de vie des composants affiné, un chargement paresseux par défaut et des objets formulaire de première classe. Si vous avez passé ces dernières années à jongler entre Vue, React et Inertia juste pour obtenir des interfaces réactives dans une application Laravel, cette version est une invitation sérieuse à revenir à la maison. Ce guide parcourt ce qui compte vraiment quand vous déployez Livewire 4 en production: pas un compteur « hello world », mais les motifs qui résistent au trafic réel.
Ce que vous allez livrer à la fin de ce guide
- Un composant Livewire 4 utilisant des objets formulaire, la validation et le chargement paresseux
- L'interopérabilité avec Alpine pour des finitions côté client sans quitter le modèle piloté par le serveur
- Un flux de téléversement de fichier avec progression, validation et stockage S3
- Des tests Pest qui pilotent le composant de bout en bout
- Checklist de production : mise en cache, versionnement des assets et les pièges qui mordent à l'échelle
Info
À qui s'adresse ce guide
Vous êtes à l'aise avec les routes, les contrôleurs et Eloquent de Laravel. Vous avez peut-être déjà utilisé Livewire 2 ou 3. Nous n'allons pas nous arrêter pour expliquer artisan ou composer.
Pourquoi Livewire 4 change la donne
Livewire 3 était la réécriture qui a rendu le framework vraiment rapide. Livewire 4 en est le polissage : les composants paresseux sont désormais le comportement par défaut pour les points d'entrée routés, les objets formulaire ont remplacé les propriétés publiques ad-hoc comme motif canonique, et la nouvelle primitive d'îlots vous permet de rendre indépendantes certaines parties d'une page pour des re-rendus séparés. Résultat : moins de données échangées, des diffs plus petits et beaucoup moins de cette douleur du « tout se re-rend à chaque frappe » qui a plombé Livewire 2.
✓ Avantages
- Pas d'API ni de contrat JSON à maintenir: le fil est invisible
- La validation côté serveur est la validation ; pas de duplication
- L'autorisation, le chargement eager et Eloquent fonctionnent « tout simplement »
- Les tests Pest pilotent les composants sans navigateur
✕ Inconvénients
- Les interfaces sensibles à la latence (glisser-déposer, curseurs, canvas) nécessitent encore Alpine ou une vraie SPA
- Chaque composant fait un aller-retour avec toutes ses propriétés: gardez-les légères
- Les actions de longue durée doivent être dispatchées dans des jobs, sans bloquer la requête
1. Objets formulaire : le motif le plus important de Livewire 4
Arrêtez de mettre les champs de formulaire directement sur votre composant. Un objet formulaire encapsule l'état, les règles et l'appel de persistance: le composant devient une coquille mince.
<?php
namespace App\Livewire\Forms;
use App\Models\Project;
use Livewire\Attributes\Validate;
use Livewire\Form;
class ProjectForm extends Form
{
public ?Project $project = null;
#[Validate('required|string|min:3|max:120')]
public string $name = '';
#[Validate('nullable|string|max:2000')]
public string $description = '';
#[Validate('required|in:draft,active,archived')]
public string $status = 'draft';
public function setProject(Project $project): void
{
$this->project = $project;
$this->name = $project->name;
$this->description = $project->description ?? '';
$this->status = $project->status;
}
public function save(): Project
{
$this->validate();
$project = $this->project
? tap($this->project)->update($this->only(['name', 'description', 'status']))
: Project::create($this->only(['name', 'description', 'status']));
$this->reset();
return $project;
}
}
Et le composant qui l'utilise :
<?php
namespace App\Livewire\Projects;
use App\Livewire\Forms\ProjectForm;
use App\Models\Project;
use Livewire\Attributes\Lazy;
use Livewire\Component;
#[Lazy]
class Edit extends Component
{
public ProjectForm $form;
public function mount(Project $project): void
{
$this->authorize('update', $project);
$this->form->setProject($project);
}
public function update(): void
{
$project = $this->form->save();
$this->dispatch('project-saved', id: $project->id);
session()->flash('status', 'Project updated.');
}
public function render(): \Illuminate\View\View
{
return view('livewire.projects.edit');
}
}
Conseil de pro
L'attribut #[Lazy] signifie que le composant affiche un placeholder au premier rendu et s'hydrate une fois la page interactive. Pour les tableaux de bord avec trois composants ou plus, ce simple attribut peut réduire le Time to Interactive de 30 à 50 %.
2. Interopérabilité avec Alpine sans perdre la tête
Livewire 4 est livré avec un pont Alpine plus étroit. Utilisez wire:model.live.debounce.500ms pour les champs qui doivent atteindre le serveur, et Alpine pour tout ce qui ne devrait jamais quitter le navigateur: ouverture/fermeture, pièges de focus, transitions.
<div x-data="{ open: false }" class="rounded-xl border bg-white p-4">
<div class="flex items-center justify-between">
<h3 class="font-semibold">{{ $form->name ?: 'Untitled project' }}</h3>
<button type="button" @click="open = !open" class="text-sm text-teal-600">
<span x-text="open ? 'Hide details' : 'Show details'"></span>
</button>
</div>
<div x-show="open" x-collapse>
<input
type="text"
wire:model.live.debounce.500ms="form.name"
class="mt-3 w-full rounded-lg border-gray-300"
/>
@error('form.name') <p class="text-rose-600 text-sm">{{ $message }}</p> @enderror
</div>
<button wire:click="update" wire:loading.attr="disabled" class="mt-4 rounded-lg bg-teal-600 px-4 py-2 text-white">
<span wire:loading.remove>Save</span>
<span wire:loading>Saving…</span>
</button>
</div>
Attention
Ne liez pas l'état Alpine à wire:model
Alpine et Livewire se disputent le même DOM. Utilisez Alpine pour l'état éphémère de l'interface (modales, accordéons) et Livewire pour l'état persistant des formulaires. Mélanger les deux crée des boucles de mise à jour infinies.
3. Téléversements de fichiers avec progression et S3
Les téléversements sont la principale raison pour laquelle les équipes se tournent vers les frameworks SPA. Livewire 4 les gère proprement : téléversement local temporaire, validation, puis dispatch du déplacement vers S3.
use Livewire\WithFileUploads;
use Livewire\Attributes\Validate;
class ProjectAttachments extends Component
{
use WithFileUploads;
public Project $project;
#[Validate(['files.*' => 'file|max:10240|mimes:pdf,png,jpg,docx'])]
public array $files = [];
public function save(): void
{
$this->validate();
foreach ($this->files as $file) {
$path = $file->storePubliclyAs(
"projects/{$this->project->id}",
Str::uuid().'.'.$file->getClientOriginalExtension(),
's3'
);
$this->project->attachments()->create([
'path' => $path,
'size' => $file->getSize(),
'mime' => $file->getMimeType(),
]);
}
$this->files = [];
$this->dispatch('attachments-saved');
}
}
Configurez le disque temporaire
Dans config/livewire.php, définissez "temporary_file_upload.disk" sur "s3" et "directory" sur "livewire-tmp". Sans cela, les gros téléversements atterrissent d'abord sur le système de fichiers local et cassent lors des déploiements horizontaux.
Ajoutez une règle CORS sur votre bucket S3
Autorisez PUT et GET uniquement depuis le domaine de votre application. Livewire émet une URL présignée pour le navigateur, le bucket doit donc accepter le téléversement directement.
Ajoutez une règle de cycle de vie
Supprimez automatiquement les objets sous "livewire-tmp/" après 24 heures. Les téléversements abandonnés s'accumulent sinon indéfiniment.
4. Tester les composants avec Pest
Les helpers de test Livewire se composent avec Pest de manière fluide. Pas de navigateur headless, pas d'attentes instables.
use App\Livewire\Projects\Edit;
use App\Models\Project;
use App\Models\User;
it('updates a project owned by the user', function () {
$user = User::factory()->create();
$project = Project::factory()->for($user, 'owner')->create(['name' => 'Old']);
actingAs($user)
->livewire(Edit::class, ['project' => $project])
->set('form.name', 'Renamed Project')
->call('update')
->assertHasNoErrors()
->assertDispatched('project-saved');
expect($project->fresh()->name)->toBe('Renamed Project');
});
it('rejects updates from non-owners', function () {
$project = Project::factory()->create();
$intruder = User::factory()->create();
actingAs($intruder)
->livewire(Edit::class, ['project' => $project])
->assertForbidden();
});
5. Checklist de production
✓ À faire
- Exécutez `php artisan livewire:publish --assets` et servez les assets via votre CDN
- Définissez correctement APP_URL: Livewire signe les URLs avec
- Mettez en cache les vues et les routes (`view:cache`, `route:cache`)
- Configurez la gestion `wire:offline` pour les réseaux instables
✕ À éviter
- N'activez pas `wire:poll` sur plus d'un composant par page: cela s'empile
- Évitez de passer de gros modèles Eloquent comme propriétés: Livewire les sérialise à chaque requête
- Les propriétés publiques d'un composant sont envoyées au navigateur ; n'y assignez jamais de secrets
moins de JS livré par rapport à un tableau de bord équivalent Inertia + Vue
Danger
Le bug numéro 1 en production
Oublier que les propriétés publiques sont visibles par le client. Si vous définissez <code>public User $user</code>, le modèle entier est hydraté et envoyé à chaque requête Livewire. Utilisez <code>#[Locked]</code> pour les propriétés que le client ne doit jamais modifier, et préférez les IDs aux modèles complets quand c'est possible.
Où Livewire 4 est pertinent, et où il ne l'est pas
Livewire est désormais le choix par défaut pour les panneaux d'administration, les pages de paramètres, les tableaux de bord, les formulaires en plusieurs étapes et la plupart des opérations CRUD. En revanche, il n'est pas adapté aux éditeurs collaboratifs, aux canevas en temps réel ou à tout scénario exigeant un retour en moins de 50 ms à chaque frappe. Dans ces cas-là, appuyez-vous sur Alpine pour la couche d'interaction et sur Livewire pour persister le résultat.
Succès
Mettez en production
Un tableau de bord Livewire 4, déployé sur une machine Forge à 20 $ derrière Cloudflare, supportera sans peine des milliers d'utilisateurs authentifiés. N'optez pour une SPA que lorsque les exigences du produit l'imposent vraiment.
Commentaires
0Aucun commentaire pour l’instant. Soyez la première personne à donner votre avis.