DEV Community

vimuth
vimuth

Posted on

Create a Chat with Laravel and Socket.io

Previously we created a chat with pusher. but this time we are going to do it with Socket.io. Socket.io is a NodeJS library. With it we can create our own servers. This is cheaper than using pusher server and we have more control on the code.

This is how to do it.

1. First we create a node server.

Install NodeJS and run this command

npm init
Enter fullscreen mode Exit fullscreen mode

And then run these command to install ioredis and sockets.io

npm i express ioredis socket.io
Enter fullscreen mode Exit fullscreen mode

Now your package.json should look like this

{
  "name": "node",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.19.2",
    "ioredis": "^5.4.1",
    "socket.io": "^4.7.5"
  }
}
Enter fullscreen mode Exit fullscreen mode

Now create a file called index.js in root and add this code.

var server = require('http').Server();

var io = require('socket.io')(server, {
    cors: {
        origin: "*",  // Allows all origins
        methods: ["GET", "POST"]  // Allowed request methods
    }
});

const { json } = require('express');
var Redis = require('ioredis');
var redis = new Redis();

redis.subscribe('chats');

redis.on('message', function (channel, message) {
    message = JSON.parse(message);
    io.emit('chatsocket', message.data);
})


server.listen(3000);
Enter fullscreen mode Exit fullscreen mode

Here it get's data from chats channel from redis and emit or send data via chatsocket channel for socket.io.

Now let's got to laravel application. We should setup all everything as previous pusher tutorial. But we have to do few things different.

in resources\js\components\Chat.vue

<template>
    <div v-if="!username">
        <input type="text" v-model="tempUsername" placeholder="Enter your username">
        <button @click="setUsername">Join Chat</button>
    </div>
    <div class="chat-box" v-else>
        <div class="chat-box-header">Chat</div>
        <div class="chat-box-messages" id="chat-messages">
            <div v-for="message in messages" :key="message.message_text" 
                :class="message.user == username ? 'message current-user' : 'message other-user'">
                {{ message.message_text }}
            </div>

        </div>
        <div class="chat-box-input">
            <input type="text" v-model="newMessage" class="input_border" placeholder="Type a message..." />
            <button type="button" @click="setMessage">Send</button>
        </div>
    </div>
</template>

<script setup>
    var socket = io('http://localhost:3000');

    import { onMounted, ref } from 'vue';

    const username = ref('');
    const tempUsername = ref('');
    const messages = ref([]);
    const newMessage = ref('');

    const setUsername = () => {
        username.value = tempUsername.value.trim();
        tempUsername.value = ''; 
    };

    const setMessage = () => {
        axios.post('/chat', {
            user: username.value,
            message_text: newMessage.value
        }).then(() => {
            let message = {
                user: username.value,
                message_text: newMessage.value
            }
            messages.value.push(message);
            newMessage.value = ""; 
        });
    }

     onMounted(async () => {

        socket.on('chatsocket', (data) => {
            let message = {
                user: data.chat.user,
                message_text: data.chat.message_text
            }

            messages.value.push(message);
        })
     });

</script>
Enter fullscreen mode Exit fullscreen mode

Here we have used socket.io client and getting the event from Nodejs Server. And we send the message using the Redis. For this we need predis installed and configured in env.

And importantly you have to change prefix => '' in config\database.php,

 'options' => [
            'cluster' => env('REDIS_CLUSTER', 'redis'),
            'prefix' => '',
            // 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
        ],
Enter fullscreen mode Exit fullscreen mode

Top comments (0)