These are my notes on how I got all the basics working end to end.
Laravel API backend and Vue.js frontend are 2 different servers on different public IP addresses and different domains. I am using pure Vue.js on the front end. Most instructions assume Laravel Vue.js is being used which is structured slightly different with different file names and directories.
- Laravel API backend domain name (api.somedomain.com)
- Vue.js frontend domain name (client.somedomain.com)
No database is needed for any of this to work using sync queue. That is only needed in production if/when you use a database queue.
composer require beyondcode/laravel-websockets
php artisan vendor:publish --provider="BeyondCode\LaravelWebSockets\WebSocketsServiceProvider" --tag="config"
Make sure App\Providers\BroadcastServiceProvider::class
is uncommented
config/app.php
'providers' => [
...
App\Providers\BroadcastServiceProvider::class,
],
.env
BROADCAST_DRIVER=pusher
QUEUE_CONNECTION=sync
PUSHER_APP_ID=testapp
PUSHER_APP_KEY=websocketkey
PUSHER_APP_SECRET=somethingsecret
PUSHER_APP_CLUSTER=mt1
config/broadcasting.php
'connections' => [
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
//'useTLS' => false,
'encrypted' => true,
'host' => '127.0.0.1',
'port' => 6001,
'scheme' => 'http',
],
],
...
config/websockets.php
'apps' => [
[
'id' => env('PUSHER_APP_ID'),
'name' => env('APP_NAME'),
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'path' => env('PUSHER_APP_PATH'),
'capacity' => null,
'enable_client_messages' => true,
'enable_statistics' => true,
],
],
routes/api.php
Route::get('test', function () {
event(new App\Events\Test());
return "Event has been sent!";
});
routes/channels.php
// This is only for testing purposes
Broadcast::channel('testchannel', function ($user) {
return true;
});
// This is probably closer to what most would use in production
Broadcast::channel('user.{id}', function ($user, $id) {
//return true if api user is authenticated
return (int) $user->id === (int) $id;
});
app/Http/Middelware/VerifyCsrfToken.php
protected $except = [
'broadcasting/auth',
];
app/Events/Test.php
<?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 Test implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct()
{
//
}
public function broadcastOn()
{
return new PrivateChannel('testchannel');
}
}
php artisan websockets:serve
npm install --save laravel-echo pusher-js
.env
Note: The variable MUST be prefixed with VUE_APP_
https://cli.vuejs.org/guide/mode-and-env.html#modes
VUE_APP_PUSHER_APP_KEY='websocketkey'
Add Echo globally. In laravel vue that file is usually called bootstrap.js. In pure Vue.js it is called main.js
main.js
import Echo from 'laravel-echo'
window.Pusher = require('pusher-js')
// This assumes you have already saved your bearer token in your browsers local storage
const token = localStorage.getItem('user-token')
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.VUE_APP_MIX_PUSHER_APP_KEY,
wsHost: 'api.somedomain.com',
authEndpoint: 'http://api.somedomain.com/broadcasting/auth',
encrypted: true,
forceTLS: false,
wsPort: 6001,
wssPort: 6001,
disableStats: true,
enabledTransports: ['ws', 'wss'],
auth: {
headers: {
authorization: 'Bearer ' + token,
}
}
})
src/App.vue
...
created() {
window.Echo.private('testchannel')
.listen('Test', (e) => {
console.log('test successful ' + e)
})
All done. Now open your src/App.vue Single Page App in a chrome/firefox browser with the developer/inspect console window opened.
In a separate browser tab/window browse to http://api.somedomain.com/test to fire the test event. You should see "test successful" showing up in your SPA page developer console.
The end.
How to keep the connection alive or deal with inactive window ? I'm encountering some strange behaviour that I can't explain