Zum Inhalt springen

đź§  Build a Real-Time Chat App in Laravel Using Reverb + Blade + Alpine.js

Laravel Reverb is changing the game for real-time applications. If you’re looking to build a live chat system without relying on third-party services like Pusher, you’re in the right place.

I’ll guide you through building a real-time public chat app step by step using:

  • Laravel Reverb (WebSocket broadcasting)
  • Laravel Breeze (Blade + Alpine.js)
  • Tailwind CSS
  • Laravel Echo on the frontend

You’ll also learn how to avoid common pitfalls, debug broadcast issues, and get this thing working in a production-friendly way.

đź§Ş Prefer Cloning? Use This Repository

If you’d like to skip the setup and just see how it’s done, feel free to clone the full project from GitHub:

đź”— GitHub Repository
👉 https://github.com/Tahsin000/reverb-live-chat

git clone https://github.com/Tahsin000/reverb-live-chat.git
cd reverb-live-chat
composer install
npm install && npm run dev
cp .env.example .env
php artisan key:generate
php artisan migrate
php artisan reverb:start
php artisan serve

Now open http://localhost:8000/chat — and you’re in!

🎯 What You’ll Build

A public real-time chat app where:

  • Users send/receive messages instantly
  • Everything updates live with WebSocket (Reverb)
  • The UI is clean and responsive with Alpine.js + Tailwind

🔧 Manual Setup (If You’re Building It Yourself)

Step 1: Create New Project & Install Breeze

laravel new reverb-live-chat
cd reverb-live-chat
composer require laravel/breeze --dev
php artisan breeze:install
npm install && npm run dev
php artisan migrate
php artisan serve

Step 2: Install and Start Laravel Reverb

php artisan install:reverb
php artisan reverb:start

Update .env:

BROADCAST_DRIVER=reverb

Step 3: Create Message Model + Migration

php artisan make:model Message -m

Update migration:

$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('content');
$table->string('room')->default('public');

Run:

php artisan migrate

In Message.php:

protected $fillable = ['user_id', 'content', 'room'];

public function user() {
    return $this->belongsTo(User::class);
}

Step 4: Create and Broadcast Event

php artisan make:event MessageSent

In MessageSent.php:

class MessageSent implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(public Message $message) {}

    public function broadcastOn(): Channel
    {
        return new Channel('chat.public');
    }

    public function broadcastWith(): array
    {
        return [
            'message' => $this->message->load('user'),
        ];
    }
}

Add logging if needed:

Log::info('MessageSent Event fired', ['message' => $this->message]);

Step 5: ChatController

php artisan make:controller ChatController

Add methods:

public function fetch($room = 'public') {
    return Message::with('user')->where('room', $room)->latest()->get();
}

public function send(Request $request) {
    $message = Message::create([
        'user_id' => auth()->id(),
        'content' => $request->content,
        'room' => $request->room ?? 'public',
    ]);

    broadcast(new MessageSent($message))->toOthers();

    return response()->json(['status' => 'Message Sent!']);
}

Step 6: Routes

Route::middleware('auth')->group(function () {
    Route::view('/chat', 'chat');
    Route::get('/chat/messages', [ChatController::class, 'fetch']);
    Route::post('/chat/send', [ChatController::class, 'send']);
});

Step 7: chat.blade.php

@extends('layouts.app')

@section('content')
<div class="container mx-auto mt-10" x-data="chatApp()" x-init="init()">
    <h2 class="text-xl font-bold mb-4">Live Chat</h2>

    <div class="border p-4 h-96 overflow-y-scroll mb-4 bg-gray-100 rounded">
        <template x-for="msg in messages" :key="msg.id">
            <div class="mb-2">
                <strong x-text="msg.user.name"></strong>: 
                <span x-text="msg.content"></span>
            </div>
        </template>
    </div>

    <form @submit.prevent="sendMessage" class="flex gap-2">
        <input type="text" x-model="newMessage" class="flex-1 border p-2 rounded" placeholder="Type your message..." required>
        <button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded">Send</button>
    </form>
</div>
@endsection

@push('scripts')
<script src="//unpkg.com/alpinejs" defer></script>
<script type="module">
    import Echo from 'laravel-echo';
    import Pusher from 'pusher-js';

    window.Pusher = Pusher;

    window.Echo = new Echo({
        broadcaster: 'pusher',
        key: 'local',
        wsHost: window.location.hostname,
        wsPort: 6001,
        forceTLS: false,
        disableStats: true,
    });

    function chatApp() {
        return {
            messages: [],
            newMessage: '',
            user: @json(auth()->user()),

            init() {
                this.fetchMessages();
                Echo.channel('chat.public')
                    .listen('MessageSent', (e) => {
                        this.messages.unshift(e.message);
                    });
            },

            fetchMessages() {
                fetch('/chat/messages')
                    .then(res => res.json())
                    .then(data => this.messages = data);
            },

            sendMessage() {
                fetch('/chat/send', {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
                    },
                    body: JSON.stringify({ content: this.newMessage })
                }).then(() => this.newMessage = '');
            }
        }
    }
</script>
@endpush

đź§  Common Issues and Fixes

Issue Solution
Uncaught ReferenceError: require is not defined Use import instead of require() when working with Vite
Event not firing Check if you ran php artisan queue:work
Queue not logging Add Log::info() inside the event
$slot undefined Switch to @yield('content') in layout
Messages not showing for others Make sure to use .toOthers() when broadcasting

âś… Wrapping Up

You now have a working real-time public chat system in Laravel using native tools — no Pusher needed.

đź›  Want to learn more?
Let me know if you want:

  • Private messaging
  • Typing indicators
  • Group chat rooms

📌 GitHub Repo Again

đź”— Clone it now
👉 https://github.com/Tahsin000/reverb-live-chat

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert