In this article, we'll get real-time broadcasting working between a Nuxt SPA and Laravel using Laravel Reverb and Echo.
We only cover public channel broadcasting in this article, but our full Real-time with Nuxt and Laravel course also dives into private channels, too!
Ok, if you only need public channels, let's get started by setting up a fresh client and API project before we start.
Create a basic Laravel project with no starter kit and make sure it's accessible (for me, it'll be available at realtime-nuxt-laravel.test
using Laravel Herd).
laravel new realtime-nuxt-laravel
Create a Nuxt project with any name you like:
npx nuxi@latest init realtime-nuxt-laravel-client
Once your Nuxt client is up and running, the most important step here is to make sure both our client and API are running on the same domain. If you get into CORS with authentication later and the domains (not including subdomains) don't match, nothing will work.
To set the domain in Nuxt, open up nuxt.config.ts
and add the devServer
option with the host:
export default defineNuxtConfig({
compatibilityDate: '2024-04-03',
devtools: { enabled: false },
devServer: {
host: 'realtime-nuxt-laravel.test'
}
})
Once that's changed, get your dev server up and running, and you should be able to access your Nuxt client at realtime-nuxt-laravel.test:3000
:
npm run dev
Perfect, now we've got our client and API running... let's install Reverb.
Laravel Reverb is a WebSocket server for Laravel. Once we've installed, configured and run this, we'll be able to broadcast events to the server from Laravel and listen to events from our Nuxt client.
In your API project, start by installing broadcasting:
php artisan install:broadcasting
When this command asks you if you want to install the Node dependencies for real-time, choose No. Why? Because these dependencies need to be installed on our client.
Once broadcasting is installed, you'll see several changes to your .env
file:
BROADCAST_CONNECTION=reverb
REVERB_APP_ID=334045
REVERB_APP_KEY=kscaenynxvk85d6pm8kj
REVERB_APP_SECRET=76ac2m0jo8dgufxjoh80
REVERB_HOST="localhost"
REVERB_PORT=8080
REVERB_SCHEME=http
We don't need to change any of these defaults for now.
The REVERB_APP_KEY
, REVERB_HOST
(which we'll update), and REVERB_PORT
will be useful for our client when connecting to our Reverb server.
The REVERB_APP_SECRET
is always private and won't be used on our client. This is used for our API to connect to the Reverb server to broadcast an event payload. The BROADCAST_CONNECTION
tells our API that Reverb is the driver we're using to broadcast messages.
The following command starts the Reverb server so we're able to connect to it:
php artisan reverb:start --debug
I've used the --debug
flag here to dump any output we get (when we broadcast a message or a client connects) just so we can keep an eye on things if something isn't quite working.
That's it! Reverb is installed and running, and we can now connect to the WebSocket server from our client.
To connect to our Reverb server from Nuxt, we'll use Laravel Echo. Echo is a JavaScript package that allows us to connect to a WebSocket server and subscribe to channels.
Over on your client, install both Echo and Pusher (which Echo depends on):
npm install laravel-echo pusher-js
Once that's done, we'll register these on the window
object inside a Nuxt plugin, which is pretty standard practice when using Laravel Echo.
Create a plugins
directory in the root of your Nuxt project and create a laravel-echo.client.ts
file:
import Echo from 'laravel-echo'
import Pusher from 'pusher-js'
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig()
window.Pusher = Pusher
window.Echo = new Echo({
broadcaster: 'reverb',
key: config.public.REVERB_KEY,
wsHost: config.public.REVERB_HOST,
wsPort: 8080,
cluster: 'mt1',
forceTLS: false
})
})
This adds Echo
to our window
object, and we're now able to access it anywhere in our Nuxt components to join and listen on channels.
You'll notice the REVERB_KEY
and REVERB_HOST
is defined from config here, so start by creating an .env
file in the root of your Nuxt project:
API_URL=http://realtime-nuxt-laravel.test
REVERB_KEY=kscaenynxvk85d6pm8kj
REVERB_HOST=realtime-nuxt-laravel.test
And then add this runtime configuration to nuxt.config.ts
, as well as the plugin you just created:
export default defineNuxtConfig({
compatibilityDate: '2024-04-03',
devtools: { enabled: false },
devServer: {
host: 'realtime-nuxt-laravel.test'
},
plugins: [
'~/plugins/laravel-echo.client'
],
runtimeConfig: {
public: {
API_URL: process.env.API_URL,
REVERB_KEY: process.env.REVERB_KEY,
REVERB_HOST: process.env.REVERB_HOST,
}
}
})
The .client.ts
extension we used for the plugin tells Nuxt to only use this plugin on the client. There's no need to listen to WebSockets when using SSR.
That's our Laravel Echo plugin created. Let's make sure we're getting a connection to our Reverb server next.
To test a connection to our Reverb server, start by updating app.vue
to look like this:
<script setup lang="ts">
onMounted(() => {
window.Echo.channel('public')
.listen('ExampleEvent', (e: any) => {
console.log(e)
})
})
</script>
<template>
<div></div>
</template>
This attempts to connect to a public
channel using Laravel Echo. Open up the dev tools in your browser, head to the Network tab and filter by WS (WebSockets).
You should see a 101 Switching Protocols status for the connection to Reverb. If that's the case, you're successfully connected to your WebSocket server and can start to receive broadcasted events.
If you're connected to your Reverb server from the last step, the great news is that you can now broadcast and listen to events on public channels.
Start by creating an event in your API:
php artisan make:event ExampleEvent
Update your ExampleEvent
by implementing the ShouldBroadcastNow
interface, add some example payload data as a public property and switch over the channel type and name:
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
class ExampleEvent implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public string $greeting = 'Hello';
/**
* 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 Channel('public'),
];
}
}
To trigger this event, we'll create an API route that we'll hit from our client.
To install Laravel's API functionality, run this command:
php artisan install:api
Once that's done, head over to routes/api.php
and add a route to broadcast the event we just created:
use App\Events\ExampleEvent;
Route::post('/realtime', function () {
broadcast(new ExampleEvent());
});
Back in your Nuxt app, update app.vue
with a button and handler to make an HTTP request to this endpoint:
<script setup lang="ts">
const config = useRuntimeConfig()
onMounted(() => {
window.Echo.channel('public')
.listen('ExampleEvent', (e: any) => {
console.log(e)
})
})
const sendRequest = () => {
$fetch('/api/realtime', {
baseURL: config.runtime.API_URL,
method: 'POST'
})
}
</script>
<template>
<div>
<button v-on:click="sendRequest">Send request</button>
</div>
</template>
Using the API_URL
we added earlier as the baseURL
, this will now hit our API endpoint and broadcast our ExampleEvent
to the Reverb server.
Because we're listening on the public
channel for the ExampleEvent
, you should now see the payload logged out to your browser console. If you do, you've successfully set up real-time broadcasting with Nuxt and Laravel!
If you're a visual learner, would like to dive into how this works in detail or would like to learn how to authorize private channels, our Real-time with Nuxt and Laravel covers everything you need to do this.
Happy broadcasting!