Skip to content

Rift v0.2.2 — Versioning, Lifecycle Hooks & Sync Proxy Upgrade

Choose a tag to compare

@singlephon singlephon released this 27 Jul 23:19
· 4 commits to master since this release

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); 
    }
}

Output:
image

  • 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) {}
}