Overview Laravel Reverb marks a significant milestone in the Laravel ecosystem. As a first-party, high-performance WebSocket server, it eliminates the historical friction of integrating real-time features into PHP applications. Traditionally, developers had to rely on third-party services like Pusher or complex Node.js setups to handle bi-directional communication. Reverb changes this by bringing the entire infrastructure under the Laravel umbrella, allowing for seamless integration with Livewire and Alpine.js. This guide explores how to build a collaborative environment where users can see each other's actions instantly. We will implement a shared toggle switch and a real-time cursor tracking system similar to collaborative tools like Figma. By the end of this tutorial, you will understand how to manage state across multiple clients, broadcast events efficiently, and deploy a production-ready WebSocket server using Laravel Forge. Prerequisites To follow along effectively, you should be comfortable with: * **PHP and Laravel 11**: Basic understanding of routing, controllers, and Eloquent. * **Livewire Volt**: Familiarity with the class-based API for single-file components. * **JavaScript (Alpine.js)**: Basic knowledge of reactive front-end directives like `x-data` and `x-on`. * **Terminal/CLI**: Ability to run Artisan commands and manage NPM packages. * **Local Environment**: Laravel Herd is highly recommended for its built-in Reverb support, but a standard Laravel setup works as well. Key Libraries & Tools * Laravel Reverb: The core WebSocket server handling real-time data transmission. * Livewire Volt: A single-file component syntax for Livewire that keeps logic and templates unified. * Laravel Echo: The JavaScript library used to subscribe to channels and listen for events on the client side. * Alpine.js: Handles local UI state and ensures "optimistic" updates for a snappier user experience. * **Font Awesome**: Provides the visual icons for our cursor effects. Code Walkthrough: The Multi-Player Toggle Our first task is creating a toggle switch that stays in sync for every user currently on the site. We use a combination of database caching and event broadcasting to ensure state persistence. 1. Scaffolding the Component Generate the Volt component using the following command: ```bash php artisan make:volt toggle ``` In the component, we define the `toggle_switch` property and use the `mount` method to retrieve the initial state from the cache. This ensures that if a new user joins, they see the current state immediately. ```php public bool $toggle_switch = false; public function mount() { $this->toggle_switch = Cache::get('toggle_switch', false); } ``` 2. The Broadcasting Event We need a dedicated event class to signal the WebSocket server. Create it with `php artisan make:event SwitchFlipped`. Crucially, this event must implement `ShouldBroadcastNow` to bypass the queue and send data immediately. ```php class SwitchFlipped implements ShouldBroadcastNow { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct(public bool $toggle_switch) {} public function broadcastOn(): array { return [new Channel('switch')]; } public function broadcastWith(): array { return ['toggle_switch' => $this->toggle_switch]; } } ``` 3. Triggering the Flip Inside the Volt component, the `flipSwitch` method updates the cache and broadcasts the new state to all other connected clients. ```php public function flipSwitch() { Cache::forever('toggle_switch', $this->toggle_switch); broadcast(new SwitchFlipped($this->toggle_switch))->toOthers(); } ``` On the front end, we use Alpine.js to entangle the local state with the Livewire property. This creates an "optimistic UI" where the switch moves instantly for the user who clicked it, while the server call happens in the background. ```html <div x-data="{ localToggle: $wire.entangle('toggle_switch') }"> <input type="checkbox" x-model="localToggle" x-on:change="$wire.flipSwitch()"> </div> ``` Syntax Notes: Attributes and Entanglement The `On` Attribute Livewire provides a powerful PHP attribute, `#[On]`, which allows your component to listen for client-side events directly within the class. When using Reverb, we prefix the event name with `echo:`. This tells Livewire to listen to the WebSocket channel rather than a standard internal event. ```php #[On('echo:switch,SwitchFlipped')] public function handleBroadcast($payload) { $this->toggle_switch = $payload['toggle_switch']; } ``` State Entanglement The `$wire.entangle()` method is the bridge between Alpine.js (client-side) and Livewire (server-side). It creates a two-way binding. If you change a variable in Alpine, it reflects in Livewire, and vice versa. This is critical for real-time apps because it allows the UI to react to broadcasts without full page reloads. Practical Examples: Advanced Cursor Tracking Beyond simple toggles, we can track mouse movements to create a collaborative workspace. This requires calculating cursor positions relative to the screen center so that users on different monitor sizes see the pointer in the correct logical position. Calculating Relative Position In our JavaScript, we calculate the offset from the center of the viewport. This prevents the cursor from appearing "broken" when users have different browser window dimensions. ```javascript const relativeX = (e.clientX - (window.innerWidth / 2)) / (window.innerWidth / 2); const relativeY = (e.clientY - (window.innerHeight / 2)) / (window.innerHeight / 2); ``` We then send these coordinates to the Livewire component, which broadcasts them via a `MouseMoved` event. To prevent overwhelming the server with hundreds of events per second, we implement a slight throttle or check to ensure the mouse has actually moved a significant distance before broadcasting. Smooth Cursor Animation Directly binding a `div` to the coordinates received from a broadcast can look choppy due to network latency. To fix this, we use a requestAnimationFrame loop in Alpine.js to interpolate the cursor's current position toward the target position, creating a fluid, professional feel. Tips & Gotchas * **Queue vs. Now**: By default, Laravel events are queued. In real-time apps, this can cause a noticeable lag. Always use `ShouldBroadcastNow` for interactions that require immediate feedback, like mouse movement or chat messages. * **Environment Variables**: Ensure your `.env` file has `BROADCAST_CONNECTION=reverb`. If you're using Herd, it manages the credentials for you, but on a manual setup, you must verify the `REVERB_APP_ID` and `REVERB_APP_KEY` match your server configuration. * **Browser Backgrounding**: Browsers often throttle JavaScript in background tabs. We added a `visibilitychange` listener to stop broadcasting cursor data when a user switches tabs. This saves server resources and keeps the active user count accurate. * **Sticky Sessions**: When deploying to production, ensure your load balancer (if using one) supports WebSockets. Reverb handles the connections, but your infrastructure must allow the long-lived HTTP connection to remain open.
WebSocket
Concepts
Jul 2024 • 1 videos
High activity month for WebSocket. Laravel among the most active voices, with 1 videos across 1 sources.
Jul 2024
- Jul 9, 2024