Livewire v3

Après 2 ans de développement et une réécriture complète, Caleb Porzio a annoncé le 23 août dernier la sortie de Livewire 3 !

Traduction de l’article « Livewire v3 Has Been Released » de Jason Beggs publié sur Laravel News.

Noyau réécrit

Le cœur de Livewire a été totalement réécrit à partir de zéro. La réécriture du noyau était une entreprise énorme, mais elle était nécessaire pour accomplir tout ce qui est inclus dans cette version. La nouvelle architecture de base sera également beaucoup plus facile à maintenir pour Caleb et les principaux contributeurs de Livewire.

Utilisation de Alpine

Le noyau v3 utilise désormais Alpine à son plein potentiel. Au lieu d’inclure du code pour appliquer les mises à jour DOM, ajouter des event listeners, etc., à la fois dans Livewire et Alpine, Livewire v3 utilise Alpine pour le gros du travail.

En enregistrant les plugins Alpine, Livewire permet désormais à Alpine de faire le gros du travail tout en fournissant le « sucre syntaxique » que vous aimez.

Cela signifie également qu’Alpine est désormais inclus par défaut avec Livewire, il n’est donc pas nécessaire de charger Alpine via un CDN ou NPM. Il est injecté automatiquement.

De plus, la v3 utilise le plugin Alpine Morph pour comparer le DOM et appliquer des mises à jour au lieu du morphdom. Cela entraînera moins de problèmes de différence DOM et une meilleure compatibilité globale entre Livewire et Alpine.

Imbrication des composants améliorée

Dans le passé, certains considéraient l’imbrication des composants Livewire comme un anti-modèle ou quelque chose à éviter lorsque cela était possible en raison des implications potentielles en termes de performances. Avec la v3, ce ne sera plus le cas.

Avec les « reactive props », les « bundled requests », la nouvelle propriété $parent et d’autres améliorations, la v3 améliore considérablement l’imbrication des composants. Nous aborderons certaines de ces améliorations plus en détail plus loin dans cet article.

Sérialisation des propriétés améliorée

La v2 a essayé de déterminer intelligemment quels types de propriétés figuraient sur le rendu initial pour les réhydrater avec les mêmes types lors des requêtes ultérieures.

Cependant, la v2 ne prenait pas en charge l’hydratation profondément imbriquée. Si vous aviez une collection avec des types mixtes, la v2 ne restituait pas chaque élément de la collection à son type d’origine.

La v3 est beaucoup plus intelligente à ce sujet et stocke le type de chaque élément afin de pouvoir les retransformer en types appropriés lors des requêtes ultérieures.

Requêtes groupées

Dans la version 2, lorsque plusieurs composants d’une page interrogeaient ou écoutaient le même événement, Livewire envoyait des requêtes distinctes pour chaque composant chaque fois qu’il avait besoin de communiquer avec le serveur.

La v3 est beaucoup plus efficace et regroupe toutes ces mises à jour en une seule requête.

Meilleurs paramètres par défaut

Injection de marqueurs Blade

La différence DOM est l’un des problèmes les plus courants que vous pourriez rencontrer avec la v2. Le problème était généralement dû à @if et à des directives Blade similaires insérant ou supprimant des éléments DOM.

La v3 tente de contourner ces problèmes en injectant des commentaires HTML (marqueurs) là où commencent et se terminent ces directives Blade. En recherchant ces marqueurs, Livewire peut faire correspondre les éléments DOM nouveaux ou supprimés avec un marqueur pour les placer correctement dans le DOM.

1<form wire:submit="save">
2 {{-- ... --}}
3 
4 <!-- __BLOCK__ -->
5 @if ($success)
6 <div>Saved!</div>
7 @endif
8 <!-- ENDBLOCK -->
9 
10 <div>
11 <button>Save</button>
12 </div>
13<div>

wire:model est différé par défaut

À l’origine, Livewire être « en direct » était une fonctionnalité vraiment intéressante, elle est donc devenue la fonctionnalité par défaut.

Après réflexion et observation de l’utilisation dans le monde réel, Caleb s’est rendu compte que le report des requêtes wire:model était la meilleure valeur par défaut.

La plupart des applications n’ont pas réellement besoin que les valeurs d’entrée soient synchronisées avec le serveur à chaque frappe, donc la v3 inverse le comportement par défaut.

La précédente fonctionnalité wire:model.defer est la nouvelle fonctionnalité par défaut lors de l’utilisation de wire:model. Et wire:model.live a été ajouté pour remplacer l’ancien comportement par défaut sur les entrées qui doivent réellement être « en direct ».

1{{-- Now deferred by default --}}
2<input wire:model="name">
3 
4{{-- Syncs with the server on every keystroke --}}
5<input wire:model.live="name">

Nouvelles fonctionnalités

Assets injectés automatiquement

Dans la v3, Livewire injecte automatiquement ses styles, ses scripts et Alpine. Plus besoin d’ajouter <livewire:styles /> et <livewire:scripts /> ou de charger Alpine dans vos projets !

Nouveau namespace par défaut

Par défaut, la v3 utilise désormais le namespace App\Livewire (et le répertoire app/Livewire) au lieu de App\Http\Livewire. Il existe une option de configuration pour conserver l’ancien espace de noms si vous préférez.

Propriétés réactives

Issus de frameworks frontend comme React et Vue, certains utilisateurs de Livewire ont automatiquement supposé que les propriétés qu’ils avaient transmises aux composants imbriqués réagiraient aux modifications apportées au parent.

En raison de certaines limitations de la v2, cela n’était pas réellement possible. Nous avons dû nous appuyer sur des événements ou d’autres solutions de contournement pour synchroniser les composants imbriqués.

La v3 ajoute la prise en charge des propriétés « réactives ». C’est aussi simple que d’ajouter un attribut PHP #[Reactive] à la propriété de votre classe de composant.

1<?php
2 
3// ...
4use Livewire\Attributes\Reactive;
5 
6class InvoiceItem extends Component
7{
8 #[Reactive]
9 public $item;
10}

Form objects

Les objets de formulaire (form objects) sont un nouveau concept qui peut aider à garder les classes de composants propres en supprimant une partie du code spécifique au formulaire.

Vous souhaiterez peut-être placer les propriétés de formulaire, la validation, l’enregistrement et bien plus encore d’un composant sur les objets de formulaire.

Voici un petit exemple, mais je vous recommande de lire la documentation pour une liste complète des fonctionnalités !

Form object classe :

1<?php
2 
3namespace App\Livewire\Forms;
4 
5use Livewire\Form;
6 
7class UserForm extends Form
8{
9 #[Rule('required')]
10 public $name = '';
11 
12 #[Rule(['required', 'email'])]
13 public $email = '';
14}

Livewire component classe :

1<?php
2 
3namespace App\Livewire;
4 
5use Livewire\Component;
6use App\Models\Post;
7use App\Livewire\Forms\UserForm;
8 
9class UpdateProfile extends Component
10{
11 public UserForm $form;
12 
13 public function save()
14 {
15 auth()->user()->update(
16 $this->form->all()
17 );
18 
19 return $this->redirect('/profile');
20 }
21 
22 public function render()
23 {
24 return view('livewire.update-profile');
25 }
26}

Blade view :

1<form wire:submit="save">
2 <input type="text" wire:model="form.name">
3 <div>
4 @error('form.name')
5 <span class="error">{{ $message }}</span>
6 @enderror
7 </div>
8 
9 <input type="email" wire:model="form.email">
10 <div>
11 @error('form.email')
12 <span class="error">{{ $message }}</span>
13 @enderror
14 </div>
15 
16 <button type="submit">Save</button>
17</form>

Nouvel attribut wire:navigate (SPA mode)

Une autre nouveauté est wire:navigate. Lorsque vous utilisez des composants Livewire pleine page, vous pouvez désormais ajouter l’attribut wire:navigate à vos liens pour activer une expérience de type SPA.

Au lieu de charger une page entière, Livewire ajoutera un indicateur de chargement en haut de la page, récupérera le contenu de la nouvelle page en arrière-plan, puis échangera intelligemment le code HTML de la page.

La fonctionnalité prend également en charge la prélecture et les redirections et permet la persistance d’éléments.

1<a href="/profile" wire:navigate>Profile</a>

Nouvelle directive Blade @persist

Avec l’ajout de @persist , vous pouvez désormais avoir des éléments « persistants » qui ne sont pas rechargés lors de la navigation dans différentes pages via wire:navigate. Cette fonctionnalité sera pratique pour les cas d’utilisation tels que les lecteurs audio dans lesquels vous souhaitez continuer à lire de l’audio pendant que vos utilisateurs cliquent sur différentes pages.

Pour utiliser la fonctionnalité, englobez l’élément que vous souhaitez conserver dans la directive @persist :

1@persist('player')
2 <audio src="{{ $episode->file }}" controls></audio>
3@endpersist

Lazy-loaded components

Livewire prend désormais en charge les composants « lazy-loaded ». Parfois, vous avez un composant qui peut ralentir le chargement initial de la page ou qui est initialement caché dans une modal que vous souhaitez « lazily load » pour maintenir le chargement initial de la page rapide.

Pour cela, ajoutez simplement l’attribut lazy au composant dans votre vue Blade.

1<livewire:your-component lazy />

Livewire ignorera le rendu de ce composant lors du chargement initial de la page. Une fois tous les autres contenus chargés, une requête réseau sera envoyée pour restituer complètement le composant et le composant sera inséré dans le DOM.

Nouvelle propriété $parent

Pour communiquer avec les composants « parents » dans les versions précédentes de Livewire, vous deviez utiliser des events et des listeners.

Dans la v3, il existe une nouvelle propriété $parent que vous pouvez utiliser pour appeler des méthodes sur les composants parents directement à partir des enfants.

1<div>
2 <span>{{ $item->name }}</span>
3 
4 <button wire:click="$parent.remove({{ $item->id }})">Remove</button>
5</div>

Hybrid methods/evaluating JS depuis le backend

La v3 vous permet désormais d’écrire des méthodes JavaScript dans vos composants backend. En ajoutant l’attribut #[Js] à une méthode sur un composant, vous pouvez écrire du code JavaScript sous forme de chaîne de caractères et Livewire exposera cette méthode à votre interface.

Lorsqu’il est appelé via wire:click, le JavaScript sera exécuté sur le frontend sans qu’aucune requête réseau ne soit renvoyée au serveur.

Component classe :

1<?php
2 
3// ...
4use Livewire\Attributes\Js;
5 
6class UsersTable extends Component
7{
8 public $filters = [];
9 
10 #[Js]
11 public function reset()
12 {
13 return <<<'JS'
14 $wire.filters = [];
15 JS;
16 }
17 
18 // ...
19}

Vue Blade :

1<div>
2 <div>
3 <input wire:model.live="filters.active" type="checkbox">
4 <label>Only active</label>
5 </div>
6 
7 <button wire:click="reset">Reset Filters</button>
8 
9 @foreach ($users as $user)
10 {{-- ... --}}
11 @endforeach
12</div>

Parfois, il est utile d’exécuter de petits morceaux de JavaScript à partir de vos méthodes backend. La v3 permet cela via la méthode $this->js(). Appelez simplement la méthode et passez lui en argument une chaîne de JavaScript et Livewire l’exécutera sur le frontend lors du prochain rendu.

1public function save()
2{
3 // ...
4 
5 $this->js("alert('You just executed JS from the backend!')");
6}

Utilisation des attributs PHP

Les attributs PHP sont une fonctionnalité relativement nouvelle (Ndt: enfin PHP 8.0) et puissante de PHP, et Livewire v3 les utilise largement pour les fonctionnalités nouvelles et existantes.

#[Url]

Le nouvel attribut #[Url] remplace la propriété $query de la v2.

Ajoutez #[Url] au-dessus de toute propriété de votre composant et elle sera suivie dans la « query string ».

1<?php
2 
3// ...
4use Livewire\Attributes\Url;
5 
6class UsersTable extends Component
7{
8 #[Url]
9 public $filters = [];
10 
11 // ...
12}

#[On]

Le nouvel attribut #[On] remplace la propriété $listeners de la v2.

Ajoutez #[On('some-event')] au-dessus d’une méthode sur votre composant, et elle sera exécutée chaque fois que cet événement est déclenché.

1<?php
2 
3// ...
4use Livewire\Attributes\Url;
5 
6class UsersTable extends Component
7{
8 // ...
9 
10 #[On('filters-reset')]
11 public function resetFilters()
12 {
13 // ...
14 }
15}

#[Layout] et #[Title]

Les nouveaux attributs #[Layout] et #[Title] vous permettent de définir la vue de mise en page et le titre des composants pleine page. Ils peuvent être ajoutés sur la méthode render du composant ou sur la classe elle-même.

1#[Layout('layouts.app')]
2public function render()
3{
4 return view('livewire.create-post');
5}

#[Computed]

En remplacement de la syntaxe getSomeProperty de la v2 pour les propriétés calculées, nous avons l’attribut #[Computed]. Il fonctionne de la même manière que l’ancienne syntaxe mais comporte de nouveaux ajouts très puissants.

Dans la version 2, les propriétés calculées ne pouvaient être mises en cache que lors d’une seule requête. Dans la version 3, vous pouvez mettre en cache une propriété sur plusieurs requêtes et même sur plusieurs composants. Cela facilitera la mise en cache des requêtes de base de données coûteuses !

1use Livewire\Attributes\Computed;
2 
3// Cache across requests
4#[Computed(persist: true)]
5public function user()
6{
7 return User::findOrFail($this->userId);
8}
9 
10// Cache across all instances of this component
11#[Computed(cache: true)]
12public function user()
13{
14 return User::findOrFail($this->userId);
15}

#[Rule]

Le nouvel attribut #[Rule] remplace la propriété $rules et la méthode rules() de la v2.

Ajoutez #[Rule(['required', 'max:150'])] à une propriété de votre composant pour indiquer à Livewire comment la propriété doit être validée.

1<?php
2 
3// ...
4use Livewire\Attributes\Rule;
5 
6class InvoiceItem extends Component
7{
8 #[Rule(['required', 'max:120'])]
9 public $itemName;
10 
11 // ...
12}

#[Locked]

Le nouvel attribut #[Locked] vous permet d’empêcher un utilisateur de mettre à jour une propriété depuis le frontend. Vous pouvez l’utiliser comme mesure de sécurité sur les propriétés que les utilisateurs ne devraient pas pouvoir modifier.

1<?php
2 
3// ...
4use Livewire\Attributes\Locked;
5 
6class InvoiceItem extends Component
7{
8 #[Locked]
9 public $id;
10 
11 // ...
12}

Mise à jour

Le processus de mise à niveau pour la plupart des applications sera assez rapide. Il existe une commande artisan livewire:upgrade qui est inclus pour vous aider avec certaines des modifications les plus fastidieuses, vous pouvez ensuite suivre le guide de mise à niveau pour vous assurer que tout est à jour.

Ndt: je demande à voir…

Nouveau design et nom de domaine

En plus de toutes les nouvelles fonctionnalités et améliorations, le site de documentation Livewire a été entièrement repensé, reconstruit et réécrit.

La nouvelle documentation est beaucoup plus complète que la documentation v2. Elle couvre chaque fonctionnalité en détail et approfondit la façon dont Livewire gère l’hydratation, le morphing et les composants imbriqués sous le capot. Je vous recommande de lire l’intégralité du site dès que vous en avez le temps.

Une autre annonce importante est le déplacement du site de documentation vers livewire.laravel.com (Ndt : donc Livewire est officiellement supporté au sein de l’écosystème Laravel et par son équipe)