Real-time with Nuxt and Laravel

October 7th, 2024 • 6 minutes read time

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!

If you found this article helpful, you'll love our practical screencasts.
Author
Alex Garrett-Smith
Share :

Comments

No comments, yet. Be the first!