Today at Laracon, LiveWire announced a major update after nearly 2 years since the last release. The tool was popularized with Laravel 8 in 2020, but faced criticism from many developers. However, after today's news, things are looking up!
Watch
Inspiration/Motivation
Caleb Porzio, the creator of LiveWire and AlphineJS wanted to release a new update because he felt that Alpine and LiveWire were competing with each other too much. He originally envisioned the two libraries working seamlessly, however, many teams view the tools as a tradeoff.
In the upcoming release, devs can build flawless modals, forms, tables, dropdowns, etc. by leveraging both Alpine and LiveWire without increasing technical debt.
To make this possible, Caleb rewrote LiveWire from the ground up so he could rework the underlying plumbing. With a new foundation, LiveWire works like magic and contains more features.
Workflow Updates
When the latest version of LiveWire is released, developers will no longer need to worry about including scripts or even running npm/yarn scripts. Everything will be injected to your app automatically. This includes alpine.
Hot Module Replacement (HMR)
Part of the workflow update and auto injection includes HMR! But wait, unlike popular JS frameworks, you will not need to run any scripts which watch your codebase for changes! Everything just updates on the fly. Unfortunately, Caleb did not disclose how this was possible.
PHP SPA Features
LiveWire now makes it even easier to turn your PHP application into a snappy SPA which was previously only possible when using a JS framework. This is possible through new features such as transitions, client-side routing, and layout persistence.
Transitions
Now you can add some flare to your application when changes are detected. All you have to do is add a wire:transition
attribute to a dynamic element.
@foreach ($todos as $todo)
<li wire:transition>{{ $todo }}</li>
@endforeach
// Or you can do something more unique
@foreach ($todos as $todo)
<li wire:transition.opacity.duration.2500ms>{{ $todo }}</li>
@endforeach
Client Side Routing & Prefetching
PHP devs are familiar with page navigation. Previously, unless you adopted a framework and migrated a bunch of client side code to JSX, your pages would trigger a full refresh.
Now LiveWire makes it easy to only load the content you need. With the new wire:navigate
attribute apps will transition between pages like any other popular SPA.
<nav>
<a wire:navigate href="/" @active('/')>Todos</a>
<a wire:navigate.prefetch href="/about" @active('/about')>About</a>
<a wire:navigate href="/settings" @active('/settings')>Settings</a>
</nav>
Prefetching
Oh, and if you want to prefetch the page when hovering just add the wire:navigate.prefetch
attribute.
Layout Persistence
Have you ever used a SPA and wondered how it was possible to navigate between pages while simultaneously persisting state for a specific component like a music player? Well now you don't even have to think about it! Just add a line of code!
This example allows the audio player to keep playing in the background while a user navigates between pages or presses the back button! The key is to use the @persist
directive.
<body>
<x-podcast.header />
<x-podcast.body>
{{ slot }}
</x-podcast.body>
@persist('player')
<x-podcast.player />
@endpersist
</body>
PHP Annotations
LiveWire 3.0 will make heavy use of annotations so devs can quickly change application behavior. Here is a quick overview of what some of the annotations will do.
Annotation | Description |
---|---|
@js |
allows any PHP method to return pure JS. This means you can do not need to write a JS file to control your client-side logic! |
@locked |
make a property immutable. Similar to the final keyword in Java. |
@format |
Quickly format properties which hold a date type. |
@prop |
make a property reactive. For example, if the parent changes the passed in data. |
@modelable |
allow prop to be modeled by parent. When the child value changes notify the parent. |
Breaking Changes
There was only one breaking changed announced at Laracon, and that was the behavior for wire:model
. In previous version of LiveWire, the modeled data would poll the server frequently, but many developers disliked this framework assumption. In the new version, modeled data is deferred. This means the data change request is sent with the next event such as a button click.
If you need to use the old behavior, then you can easily switch back by using the wire:model.live
attribute.
Bundled Requests
Bundle requests ties into the change for wire:model
.
Previously, LiveWire would create separate requests for each component and event. This means apps that display multiple components can quickly get bogged down with network requests.
Since Caleb rewrote the underlying plumbing, LiveWire will try to group all updates together to form batch updates. So for example, if you make 3 rapid changes, LiveWire will only send 1 network request containing the 3 changes.
Reactive Props
Unfortunately, it is very difficult to extract LiveWire components into separate files. People that manage to work around this flaw have to create tons of event listeners and hacky JS/PHP to make this work.
Now LiveWire works as expected! You can pass in props like any JS framework, and if the parent mutates the data, the child will reflect the necessary changes.
class TodoCount extends \Livewire\Component
{
/** @prop */
public $todos;
public function render () {
return <<<'HTML'
<div>
Todos: {{ count($todos) }}
</div>
HTML;
}
}
// elsewhere
<livewire:todo-count :$todos />
Invoke Parent Methods
Likewise, you no longer have to hack together an event system to send data back to the parent. Now you can call parent methods directly by using the $parent
syntax.
class TodoInput extends \Livewire\Component
{
/** @modelable */
public $value = '';
public function render () {
return <<<'HTML'
<div>
<input wire:keydown.enter="$parent.add"
wire:model="value" placeholder="Todo" />
</div>
HTML;
}
}
Teleport works in PHP
Teleport is becoming hugely popular in other Frameworks for good reason. Now it is here in LiveWire! If you need to make styling your modal painless, just move it to the body tag! No need to restructure your entire project.
// somewhere in DOM
<div id="footer"></div>
// elsewhere
@teleport('#footer')
<div>teleport me to footer</div>
@endteleport
Lazy Loading
Finally, it super easy to write components which can be deferred. For example if you need to make an expensive database call, you can show the rest of the page without slowing down your application.
When you use the new lazy
attribute, the component will render after it is loaded into the DOM.
To compliment this feature, LiveWire provides a placeholder
method which acts as a temporary render method while the component is processing. This is the perfect place to render a spinner component!
class TodoCount extends \Livewire\Component
{
/** @prop */
public $todos;
public function placholder () {
return <<<'HTML'
<x-spinner />
HTML;
}
public function render () {
sleep(2);
return <<<'HTML'
<div>
Todos: {{ count($todos) }}
</div>
HTML;
}
}
// elsewhere
<livewire:todo-count :$todos lazy />
After Thoughts
I'm still a little skeptical of some of the design choices such as annotations, inline JS, and parent communication.
My main concern is how other developers will adopt these design choices. All of these features have sparked controversy in other languages and frameworks, so I imagine it will not be different for Livewire.
That said, this seems to be a huge improvement from the last version of LiveWire, and I think things are looking up. With these new features, I may consider defaulting to LiveWire for my team's projects.
Conclusion
LiveWire 3.0 looks promising. What do you think?
Top comments (3)
the client side routing is the one we needed the most
Be looking forward to livewire
Add to the discussion