Repository navigation
Rift v0.2.2 — Versioning, Lifecycle Hooks & Sync Proxy Upgrade
Rift
First alpha release of Rift, a Livewire-inspired component system for modern JavaScript frontends.
Rift enables full-duplex reactivity between backend (PHP) and frontend (JS) with lifecycle hooks, syncable properties, and deep Livewire v3 compatibility.
Core Concepts
-
RiftComponent (Base Class)
The foundational class for all JS components. It handles property synchronization, lifecycle management, deep proxying, and Livewire integration. -
DOM Interaction via Alpine.js
Rift seamlessly integrates with Alpine.js for declarative DOM binding and reactivity.
Component properties are exposed as reactive state through Alpine, similar to Livewire:
<x-rift component="counter">
<p x-text="rift.count"></p>
<button x-on:click="rift.increase()">+</button>
<button x-on:click="rift.decrease()">-</button>
{{-- You can use Livewire, Rift, Alpine, and Blade together 🔥 --}}
<p>Count from php: {{ $count }}</p>
@if($count % 2)
<h>Odd number</h>
@endif
<button wire:click="clear()">Clear</button>
</x-rift>- Deep Proxying
RiftComponent uses JavaScript Proxy to watch and intercept property mutations, enabling seamless sync between frontend and backend:
class Counter extends RiftComponent {
count = 1;
increase() {
this.count++;
this.rift.count = this.count; // Sync with backend
}
decrease() {
this.count--;
}
}- Syncable Properties
Backend properties listed in the synchronizer() array will automatically sync with the frontend component — and vice versa:
class Counter extends RiftComponent
{
public int $count = 10;
// The `$count` property will be synchronized with the frontend Rift component at the beginning.
// Even if the frontend Rift component is missing this property.
// When the count changes in either the backend or frontend component, both will synchronize with each other.
public function synchronizer(): array
{
return [
'count'
];
}
// ...
}On the JS side, you don’t need to declare count — it will be injected automatically:
class Counter extends RiftComponent {
// It doesn't matter whether your component has a count property or not.
// If a property is included in the `synchronizer` array, it will be available in your frontend component.
// You can update it by using `this.count = 123` or `this.count++`, and it will also reflect in the backend component.
increase() {
this.count++;
}
decrease () {
this.count--;
}
}Example Blade:
<x-rift component="counter">
<p x-text="rift.count"></p>
<button x-on:click="rift.increase()">+</button>
<button x-on:click="rift.decrease()">-</button>
<p>Count from php: {{ $count }}</p>
</x-rift>- Remote calls
Call backend methods directly from the frontend via this.rift.someMethod() and receive the response and vice versa:
class Counter extends RiftComponent
{
// ...
public function someFunction()
{
$this->rift->notify('Hello from backend!');
}
public function someData()
{
return [
'data' => $this->data,
'number' => 1,
];
}
}class Counter extends RiftComponent {
// ...
notify (message) {
alert (message);
}
async getData () {
const data = await this.rift.someData()
console.log(data);
}
}- Lifecycle hooks
Rift supports seven lifecycle hooks inspired by Livewire:
class Counter extends RiftComponent {
mount(snapshot) {}
boot(snapshot) {}
booted(snapshot) {}
updating(prop, value) {}
updated(prop, value) {}
syncing(snapshot) {}
synced(snapshot) {}
}