MENU

blog
スタッフブログ

dot
【Laravel 11】Laravel Reverbを使ってWebSocketでリアルタイム通信
技術

【Laravel 11】Laravel Reverbを使ってWebSocketでリアルタイム通信

こんにちは、ソリューションSecの長谷川です。
今日はLaravel11で追加されたLaravel Reverbについて紹介したいと思います。

Laravel Reverbとは

Laravel Reverb(ララベル リバーブ)とは、2024年3月にリリースされたLaravel11で新しく追加された機能であり
これまでLaravelでWeb Socketを用いたリアルタイムな処理を実装しようとすると
Laravel Echoを使ったりする必要がありました。

なお、Laravel EchoではLaravel Echo Serverというものを構築するか
別途Pusherを契約して使う必要があったのですが、ReverbはLaravelに内蔵されたWebSocketサーバを利用するので
導入の難易度は少し下がるかと思います。

では、以下でさっそくやっていってみましょう。

環境準備

まずは、Laravelの環境を準備していきます。
私はWSL2を使っていますので、Linux環境以外の場合はLaravelのGet Startedを参照してください。

Laravelのインストール

下記のURLの末尾の「PROJECT_NAME」の部分はプロジェクト名ですので
任意のものに変更してください。

curl -s "https://laravel.build/PROJECT_NAME" | bash

インストールが完了したら、Laravel SailでDocker環境を起動します。

cd PROJECT_NAME
./vendor/bin/sail up -d

これで立ち上がりましたが、ブラウザでアクセスする前にmigrationを実行しておきましょう。

./vendor/bin/sail artisan migrate

これでhttp://localhost/にアクセスするとLaravelの画面が表示されます。

Laravel Reverbのインストール

次はLaravel Reverbをインストールします。
以下のartisanコマンドでインストールすることができます。

./vendor/bin/sail artisan install:broadcasting

上記コマンドを実行して、「Would you like to install Laravel Reverb?」と聞かれたら「Yes」を選択しましょう。
さらに、そのあと「Would you like to install and build the Node dependencies required for broadcasting?」と聞かれるので
こちらも「Yes」を選択しておきます。

これでLaravel Reverbのインストールは完了です。
ただ、Reverbはデフォルトで8080ポートで通信するようになっていますのが
最初のLaravelインストール時のコマンドで作成されたdocker-compose.ymlでは
80ポート(HTTP用)と5173ポート(VITE用)しかフォワーディングされません。
なので、docker-compose.ymlに8080ポートを追加します。

services:
    laravel.test:
        // 中略
        ports:
            - '${APP_PORT:-80}:80'
            - '${VITE_PORT:-5173}:${VITE_PORT:-5173}'
            - 8080:8080 // ←ここを追加
        // 以下略

追加したら、dockerを立ち上げ直します。

./vendor/bin/sail up -d

イベントの作成

では、リアルタイムなイベントを処理するためのファイルを作成していきます。
以下のコマンドでEventを作成しましょう。

./vendor/bin/sail artisan make:event TestEvent

ここで作成したTestEventクラスの中身を見ています。

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class TestEvent
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     */
    public function __construct()
    {
        //
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('channel-name'),
        ];
    }
}

さて、これを少しだけ編集します。
まず、今回のイベントはブロードキャスト配信したいので、Illuminate\Contracts\Broadcasting\ShouldBroadcastを継承します。
さらに、クラスのメンバ変数として$messageを追加して、コンストラクタの中で$messageの中身を定義しましょう。
また33行目にある、「PrivateChannel」ですが、これは認証が成功した場合にのみ有効となります。
今回はテストですので、認証しなくてもいいように「Channel」に変更しておきます。

// 中略

class TestEvent implements ShouldBroadcast // ←implements追加
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message; // ←ここを追加

    /**
     * Create a new event instance.
     */
    public function __construct()
    {
        $this->message = 'Hello world!'; // ←ここを追加
    }

    // 中略

    public function broadcastOn(): array
    {
        return [
            new Channel('channel-name'), // ←Channelに変更
        ];
    }
}

イベントの発火

本来はきちんとしたところに定義すべきですが
今回は動作をちょっと見る程度ですので、トップページにアクセスした際に発火させましょう。

<?php

use App\Events\TestEvent; // ←ここを追加
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    TestEvent::dispatch(); // ←ここを追加
    return view('welcome');
});

routeファイルを変更したのでキャッシュしましょう。

./vendor/bin/sail artisan route:cache

ブラウザ側のメッセージ受信時の処理

先程のイベントの追加で、サーバーサイドでイベント発生時にメッセージを送るようにしたので
次はブラウザでイベントを受信したときの処理を追記していきます。

今回はbootstrap.jsに直接追記します。
Reverbを追加したときに、resources/js/bootstrap.jsも自動的に変更されているのですが
その末尾にコードを追加していきましょう。

import axios from 'axios';
window.axios = axios;

window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

/**
 * Echo exposes an expressive API for subscribing to channels and listening
 * for events that are broadcast by Laravel. Echo and event broadcasting
 * allow your team to quickly build robust real-time web applications.
 */

import './echo';

// ここから追加
Echo.channel("channel-name").listen("TestEvent", function (e) {
    console.log("received a message : " + e.message);
});

ファイルを追記したら、ビルドします。

./vendor/bin/sail npm run build

実際にメッセージを確認してみよう

さて、準備はできました。
実際に動作を確認していってみましょう。

LaravelのDockerはsailで起動済みの想定ですので、Reverbを起動します。

./vendor/bin/sail artisan reverb:start

次にQueue Workerを起動します。
リアルタイムと言っても同期処理ではなく、非同期処理となっており
Laravelのjobsテーブルにタスクをキューイングしていきます。
そのキューイングされたタスクを処理するために必要です。

./vendor/bin/sail artisan queue:work

ここまで来たら実際にブラウザを起動してみましょう。
http://localhost/にアクセスします。

ブラウザのデバッガを開いてみると、コンソールに「received a message : Hello world!」と表示されているかと思います。

ちょっと分かりづらいかもしれませんが、試しにブラウザで同じ画面を2つ開いて
コンソールを確認してみましょう。
片方向のブラウザでアクセスしたときにもう片方のブラウザのコンソールでもメッセージが表示されていれば成功です。

次回はこれをもうちょっと拡張して、簡単なチャットアプリを作ってみたいと思います。
それでは今回はこのへんで。

dot
dot
PAGETOP