Membuat Aplikasi Chat Sederhana (Realtime) Menggunakan NodeJS & Socket.io

DailyBlog.id - Di jaman sekarang ini teknologi tentunya akan selalu berkembang terus, ditambah lagi dengan sosial media yang mempermudah kita untuk saling berkomunikasi secara online. Namun dibalik komunikasi yang kalian lakukan itu tentunya ada sebuah program yang dijalankan, agar pesan kalian dapat saling terkirim secara realtime. Pada kesempatan kali ini, saya akan membagikan tutorial untuk kalian semua bagaimana cara membuat aplikasi chat yang sederhana dan chat yang dikirim itu nantinya akan tampil atau bisa dibilang, secara realtime dengan menggunakan NodeJS dan Socket.io. Jika kalian belum pernah mendengar mengenai Socket.io, saya akan kasih tau sedikit kepada kalian mengenai apa itu Socket.io?



Apa itu Socket.io?

Socket.io merupakan library JavaScript yang membantu kita dalam pembuatan aplikasi web. Dimana web tersebut membutuhkan respon secara realtime (atau bisa dibilang secara langsung). Dalam hal ini, Socket.io akan mengirimkan respon kepada 2 atau lebih client secara realtime atau langsung.

Jika kalian telah mengetahui apa itu Socket.io, maka kalian bisa melanjutkan untuk membuat aplikasi chat sederhananya. Mari kita buat aplikasi chatnya.

1. Langkah pertama, pastikan kalian sudah menginstall NodeJS di device uji coba atau di server kalian.

2. Jika sudah, kalian bisa install Express dan Socket.io di folder projek kalian dengan cara:

npm install express socket.io


3. Lalu agar bisa dijalankan scriptnya nantinya, kita harus buat terlebih dahulu web servernya. Kalian bisa buat file dengan nama index.js

4. Jika sudah, buka file index.js nya, kita deklarasi port yang akan digunakan (port yang digunakan 3000, kalian bisa ubah port tersebut) dan panggil express, http, dan socket.io nya. Dengan cara

const port       = 3000;
const express    = require('express');
const app        = express();
const http       = require('http');


5. Setelah itu buat servernya dan panggil Socket.io nya

const server     = http.createServer(app);
const {Server}   = require("socket.io");
const io         = new Server(server);


6. Jika sudah, tahap selanjutnya disini kita akan membuat fungsi escapeHtml yang nantinya digunakan agar chat tidak mengaktifkan html, dan membuat fungsi nl2br yang digunakan untuk mengaktifkan spasi enter. Untuk fungsi escapeHtml nya:

const escapeHtml = (text) =>
{
    return text
        .replace(/&/g, "&")
        .replace(/</g, "&lt;")
        .replace(/>/g, "&gt;")
        .replace(/"/g, "&quot;")
        .replace(/'/g, "&#039;");
}


Untuk fungsi nl2br nya:

const nl2br     = (str, is_xhtml) => 
{
    if (typeof str === 'undefined' || str === null)
        return '';

    const breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';
    return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2');
}


7. Jika sudah tahap pembuatan fungsi escapeHtml dan nl2br, maka tahap selanjutnya kita akan buat socket.io nya, yang nantinya digunakan untuk jembatan koneksi sama socket io client dengan server  dan melakukan pengiriman data (nama, pesan, dan waktu). kalian bisa copas script di bawah ini:

io.on('connection', (socket) => 
{
    socket.on('chat message', (msg) => 
    {
        io.emit('chat message', {nama: escapeHtml(msg.nama), pesan: nl2br(escapeHtml(msg.pesan)), waktu: msg.waktu});
    });
});


8.  Lalu agar server nanti bisa dijalankan, maka kita harus mengaktifkannya (beserta portnya tadi). Dengan cara:

server.listen(3000, () => {console.log('> Server dijalankan di port %d', port)});


9. Agar server bisa mengambil file seperti js, css, dll. Maka kalian buat folder public di dalam folder projek kalian. Nah agar servernya bisa mengambil file js, css, dll secara otomatis tanpa membuat secara manual. Kalian bisa copas script yang ada dibawah ini:

app.use(express.static(__dirname + '/public'));



Untuk script index.js secara lengkap seperti ini:

const port       = 3000;
const express    = require('express');
const app        = express();
const http       = require('http');
const server     = http.createServer(app);
const {Server}   = require("socket.io");
const io         = new Server(server);

const nl2br     = (str, is_xhtml) => 
{
    if (typeof str === 'undefined' || str === null)
        return '';

    const breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';
    return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2');
}

const nl2br     = (str, is_xhtml) => 
{
    if (typeof str === 'undefined' || str === null)
        return '';

    const breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';
    return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1' + breakTag + '$2');
}

io.on('connection', (socket) => 
{
    socket.on('chat message', (msg) => 
    {
        io.emit('chat message', {nama: escapeHtml(msg.nama), pesan: nl2br(escapeHtml(msg.pesan)), waktu: msg.waktu});
    });
});

server.listen(3000, () => {console.log('> Server dijalankan di port %d', port)});
app.use(express.static(__dirname + '/public'));


10. Pembuatan index.js telah selesai, langkah selanjutnya kalian bisa membuat file dengan nama index.html di dalam folder public . Setelah itu, kalian bisa copas script yang ada di bawah ini:

<!DOCTYPE html>
<html lang="id">
    <head>
        <title>AndspChat : Aplikasi Chat Sederhana (Realtime)</title>
        <meta content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1" name="viewport" />
        <link rel="stylesheet" href="styles.css" />
    </head>
    <body>

        <!-- Isi body -->

    </body>
</html>


11. Tidak lupa untuk mendesain halamannya, agar terlihat rapi dan cantik. Kalian bisa membuat file dengan nama styles.css di folder public dan copas css yang ada di bawah ini:

body {
    background: #f8f8f8;
    padding: 0;
    margin: 0;
    color: #444;
}
.content {
    padding: 20px;
    margin: 2em auto;
    max-width: 400px
}
.form-input-name {
    margin-top: 10em;
    text-align: center;   
}
.nama_user {
    padding: 12px;
    width: 92%;
    background: #fff;
    border: 1px solid #ddd;
    border-radius: 20px;
    -webkit-border-radius: 20px;
    margin: 18px 0;
    margin-top: 10px;
    font-size: 15px;
}
.masuk {
    background: #00979d;
    color: #fff;
    font-weight: bold;
    padding: 12px;
    border: 1px solid #00979d;
    border-radius: 20px;
    -webkit-border-radius: 20px;
    cursor: pointer;
}
.box-pesan {
    margin-top: 3em;
    background: #fff;
    box-shadow: 0 0 10px #aaa;
    -webkit-box-shadow: 0 0 10px #aaa;
    border-radius: 10px 10px 0 0;
    -webkit-border-radius: 10px 10px 0 0;
    display: none;
}
.box-pesan .header {
    background: #00979d;
    color: #fff;
    padding: 18px;
    border-radius: 10px 10px 0 0;
    -webkit-border-radius: 10px 10px 0 0;
}
.box-pesan .name_i {
    padding: 12px 10px; 
    border-bottom: 1px solid #ddd;
    margin-bottom: 8px;
    text-align: center;
}
.box-pesan .header h1 {
    margin: 10px 0;
    text-align: center;
    padding: 0
}
.box-pesan .pesan {
    height: 200px;
    overflow: auto;
    word-break: break-all;
}
.box-pesan .header .nama_us {font-weight: bold}
.form-submit-pesan {
    padding: 15px;
    border-top: 1px solid #ddd;
}
.form-submit-pesan textarea {
    width: 100%;
    height: 80px;
    border: 1px solid transparent;
    resize: none;
    margin-bottom: 10px;
}
.form-submit-pesan button {
    float: right;
    background: #00979d;
    border: 1px solid #00979d;
    color: #fff;
    font-weight: bold;
    padding: 8px 12px;
    border-radius: 15px;
    -webkit-border-radius: 15px;
    cursor: pointer;
}
.form-submit-pesan textarea:focus, .nama_user:focus {outline: none}
.clear {clear:right}
.pesan {margin: 10px}
.read-msg {margin: 15px;}
.read-msg .msg {
    background:#dcf8c6;
    color: #333;
    display: inline-block;
    padding: 12px;
    border-radius: 15px;
    max-width: 220px;
}
.read-msg .msg .rd {
    padding-right: 40px;
    position: relative;
}
.read-msg .msg .rd .waktu {
    font-size: 12px;
    bottom: 0;
    right: 0;
    position: absolute;
    color: #666;
}
.read-msg.active .msg {float: right;}
.read-msg .msg .head {
    padding: 5px 0;
    padding-bottom: 10px;
    border-bottom:1px solid #ddd;
    font-weight: bold;
    margin-bottom: 10px
}
.loader {
    display: none;
    position:fixed;
    top:50%;
    left:50%;
    transform: translate(-50%, -50%);
    width: 50px;
    height: 50px;
}


12. Dalam kasus aplikasi chat sederhana, hal pertama yang diinput adalah nama. Lalu akan tammpil box chatnya setelah menginputkan nama. Kalian bisa copas script yang ada di bawah ini:

<div class="content">
    <div class="form-input-name">
        <form method="post" class="form-masuk">
            <b>Masukan Nama Kamu</b><br/>
            <input type="text" class="nama_user" placeholder="Contoh: Andreas" /><br/>
            <button class="masuk">Mulai Kirim Pesan</button>
        </form>
    </div>

    <div class="loader">
        <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="69px" height="69px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
            <circle cx="50" cy="50" fill="none" stroke="#c9c9c9" stroke-width="6" r="35" stroke-dasharray="164.93361431346415 56.97787143782138">
                <animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform>
            </circle>
        </svg>
    </div>


    <div class="box-pesan">
        <div class="header">
            <h1 class="title">AndspChat</h1>
        </div>
        <div class="name_i">
            <b>Hai!</b> <span class="nama_us"></span>
        </div>

        <div class="pesan">
        </div>

        <div class="form-submit-pesan">
            <form method="post" class="submit_pesan">
                <textarea class="kirim_pesan" placeholder="Ketik pesan ..."></textarea> <button>Kirim</button>
                <div class="clear"></div>
            </form>
        </div>
    </div>
</div>


13. Setelah itu, kita panggil jQuery dan Socket.io nya, kalian bisa copas script yang ada di bawah ini dan letakan di dalam body

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="/socket.io/socket.io.js"></script>


14. Nah tahap yang ini merupakan tahap validasi inputan, dan pemanggilan socket io nya agar client bisa terhubung dengan server. Kalian bisa copas script yang ada dibawah ini:

<script type="text/javascript">
    $(function() 
    {
        // Deklarasi nama_user, chatId, div yang digunakan dan waktu
        let nama_user       = '';
        let chatId          = '';
        const socket        = io();
        const formJoin      = $('.form-masuk');
        const namaUser      = $('.nama_user');
        const formNama      = $('.form-input-name');
        const boxPesan      = $('.box-pesan');
        const namaUs        = $('.nama_us');
        const submitPesan   = $('.submit_pesan');
        const kirimPesan    = $('.kirim_pesan');
        const kumpulanPesan = $('.pesan');
        const loader        = $('.loader');
        const date          = Date.now();

        // Ketika form nama di klik
        formJoin.submit((e) =>
        {
            e.preventDefault();
            nama_user = namaUser.val().trim(); // Mengambil nama

            // Cek apakah karakter nama minimal 4 dan maksimal 50?
            if (nama_user.length < 4 || nama_user.length > 50)
                alert('Nama yang minimal 4 dan maksimal 50 karakter');
            else
            {
                formNama.hide(); // sembunyikan form nama
                loader.show(); // tampilkan animasi loading

                // animasi loading selesai, tampilkan box chatnya
                setTimeout(() =>
                {
                    loader.hide(); // hide animasi loadingnya
                    boxPesan.show(); // tampilkan box chat
                    namaUs.text(nama_user); // Tampilkan nama
                    
                    // Ketika submit pesan
                    submitPesan.submit((e) =>
                    {
                        e.preventDefault();
                        const pesan = kirimPesan.val().trim(); // ambil teks pesannya
                        chatId      = date; // sebagai unik id untuk kirm chat dan sebagai waktu kirim
                        
                        // Cek apakah pesan kosong?
                        if (pesan)
                        {
                            // Cek apakah pesan melebihi dari 500 karakter?
                            if (pesan.length > 500)
                                alert('Batasan pesan maksimal 500 karakter');
                            else
                            {
                                // kirim pesan ke socket io di server
                                socket.emit('chat message', {nama: nama_user, pesan: pesan, waktu: date});
                                kirimPesan.val(null); // hapus teks pesan yang ada di textarea
                            }
                        }
                    });

                    // client akan menerima respon balik pesan dari server
                    socket.on('chat message', (msg) =>
                    {
                        const ubahWaktu = new Date(msg.waktu); // buat format waktu
                        const jam       = ubahWaktu.getHours(); // format jam
                        // format menit
                        const menit     = ubahWaktu.getMinutes() >= 0 && ubahWaktu.getMinutes() <= 9 ? '0' + ubahWaktu.getMinutes() : ubahWaktu.getMinutes();

                        // Tampilan chat client
                        const appendHtml = `
                        <div class="read-msg ${msg.waktu === date ? 'active border-right' : 'border-left'}">
                            <div class="msg">
                                ${msg.waktu !== date ? '<div class="head">'+msg.nama+'</div>' : ''}
                                <div class="rd">${msg.pesan} <span class="waktu">${jam}:${menit}</span></div>
                            </div>
                        </div>
                        <div class="clear"></div>`;

                        kumpulanPesan.append(appendHtml); // masukkan chat ke dalam div

                        // Ketika client kirim pesan, maka div langsung scroll kebawah
                        kumpulanPesan.scrollTop(kumpulanPesan[0].scrollHeight);
                    });
                }, 500);
            }
        }) // end form submit nama
    });
</script>



Untuk script lengkapnya dari index.html seperti ini:

<!DOCTYPE html>
<html lang="id">
    <head>
        <title>AndspChat : Aplikasi Chat Sederhana (Realtime)</title>
        <meta content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1" name="viewport" />
        <link rel="stylesheet" href="styles.css" />
    </head>
    <body>
        <div class="content">
            <div class="form-input-name">
                <form method="post" class="form-masuk">
                    <b>Masukan Nama Kamu</b><br/>
                    <input type="text" class="nama_user" placeholder="Contoh: Andreas" /><br/>
                    <button class="masuk">Mulai Kirim Pesan</button>
                </form>
            </div>

            <div class="loader">
                <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: none; display: block; shape-rendering: auto;" width="69px" height="69px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
                    <circle cx="50" cy="50" fill="none" stroke="#c9c9c9" stroke-width="6" r="35" stroke-dasharray="164.93361431346415 56.97787143782138">
                        <animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="1s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform>
                    </circle>
                </svg>
            </div>


            <div class="box-pesan">
                <div class="header">
                    <h1 class="title">AndspChat</h1>
                </div>
                <div class="name_i">
                    <b>Hai!</b> <span class="nama_us"></span>
                </div>

                <div class="pesan">
                </div>

                <div class="form-submit-pesan">
                    <form method="post" class="submit_pesan">
                        <textarea class="kirim_pesan" placeholder="Ketik pesan ..."></textarea> <button>Kirim</button>
                        <div class="clear"></div>
                    </form>
                </div>
            </div>
        </div>
        
        <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
        <script src="/socket.io/socket.io.js"></script>
        <script type="text/javascript">
            $(function() 
            {
                // Deklarasi nama_user, chatId, div yang digunakan dan waktu
                let nama_user       = '';
                let chatId          = '';
                const socket        = io();
                const formJoin      = $('.form-masuk');
                const namaUser      = $('.nama_user');
                const formNama      = $('.form-input-name');
                const boxPesan      = $('.box-pesan');
                const namaUs        = $('.nama_us');
                const submitPesan   = $('.submit_pesan');
                const kirimPesan    = $('.kirim_pesan');
                const kumpulanPesan = $('.pesan');
                const loader        = $('.loader');
                const date          = Date.now();

                // Ketika form nama di klik
                formJoin.submit((e) =>
                {
                    e.preventDefault();
                    nama_user = namaUser.val().trim(); // Mengambil nama

                    // Cek apakah karakter nama minimal 4 dan maksimal 50?
                    if (nama_user.length < 4 || nama_user.length > 50)
                        alert('Nama yang minimal 4 dan maksimal 50 karakter');
                    else
                    {
                        formNama.hide(); // sembunyikan form nama
                        loader.show(); // tampilkan animasi loading

                        // animasi loading selesai, tampilkan box chatnya
                        setTimeout(() =>
                        {
                            loader.hide(); // hide animasi loadingnya
                            boxPesan.show(); // tampilkan box chat
                            namaUs.text(nama_user); // Tampilkan nama
                            
                            // Ketika submit pesan
                            submitPesan.submit((e) =>
                            {
                                e.preventDefault();
                                const pesan = kirimPesan.val().trim(); // ambil teks pesannya
                                chatId      = date; // sebagai unik id untuk kirm chat dan sebagai waktu kirim
                                
                                // Cek apakah pesan kosong?
                                if (pesan)
                                {
                                    // Cek apakah pesan melebihi dari 500 karakter?
                                    if (pesan.length > 500)
                                        alert('Batasan pesan maksimal 500 karakter');
                                    else
                                    {
                                        // kirim pesan ke socket io di server
                                        socket.emit('chat message', {nama: nama_user, pesan: pesan, waktu: date});
                                        kirimPesan.val(null); // hapus teks pesan yang ada di textarea
                                    }
                                }
                            });

                            // client akan menerima respon balik pesan dari server
                            socket.on('chat message', (msg) =>
                            {
                                const ubahWaktu = new Date(msg.waktu); // buat format waktu
                                const jam       = ubahWaktu.getHours(); // format jam
                                // format menit
                                const menit     = ubahWaktu.getMinutes() >= 0 && ubahWaktu.getMinutes() <= 9 ? '0' + ubahWaktu.getMinutes() : ubahWaktu.getMinutes();

                                // Tampilan chat client
                                const appendHtml = `
                                <div class="read-msg ${msg.waktu === date ? 'active border-right' : 'border-left'}">
                                    <div class="msg">
                                        ${msg.waktu !== date ? '<div class="head">'+msg.nama+'</div>' : ''}
                                        <div class="rd">${msg.pesan} <span class="waktu">${jam}:${menit}</span></div>
                                    </div>
                                </div>
                                <div class="clear"></div>`;

                                kumpulanPesan.append(appendHtml); // masukkan chat ke dalam div

                                // Ketika client kirim pesan, maka div langsung scroll kebawah
                                kumpulanPesan.scrollTop(kumpulanPesan[0].scrollHeight);
                            });
                        }, 500);
                    }
                }) // end form submit nama
            });
        </script>
    </body>
</html>



15. Dan tahap terakhir, kalian bisa buat file dengan nama package.json (jika belum ada) di folder projek kalian. Sebagai contoh isi file nya dan dependencies yang saya gunakan seperti ini:

{
  "name": "AndspChat",
  "version": "0.0.1",
  "description": "AndspChat : Chat Real Time",
  "dependencies": {
    "express": "^4.17.1",
    "socket.io": "^4.3.1"
  },
  "scripts": {
    "start": "node index.js"
  }
}


Pastikan benar pada bagian script -> start "node index.js" agar nantinya jika ingin di pasang di server kalian (contoh nodejsnya dijalankan di cPanel), bisa jalan dengan normal tanpa ada kendala.

16. Dan untuk yang di device uji coba, kalian bisa mencoba jalan kan dengan cara buka cmd/terminal. Lalu ketik seperti ini:

node index.js


Pastikan saat membuka cmd/terminal nya di direktori projek kalian. Dan ketika dijalankan, hasilnya akan seperti ini:

Membuat Aplikasi Chat Sederhana (Real Time) Menggunakan NodeJS dan Socket.io

Setelah itu kalian bisa buka url nya (Contoh: http://localhost:3000). Maka hasil input nama dan input pesannya akan seperti ini:

Membuat Aplikasi Chat Sederhana (Real Time) Menggunakan NodeJS dan Socket.io


Bukti realtime saling kirim chat di 2 browser yang berbeda:



Nah untuk client bisa lebih dari 2 orang, dan bisa saling kirim pesan nantinya. Gimana? keren kan. Nanti kirim pesannya bisa secara realtime atau secara langsung tanpa ada delay antar client. Biasanya Socket.io ini sangat cocok digunakan untuk aplikasi Live Chat, lalu menampilkan notifikasi yang secara realtime. Sangat mudah kan? kalian bisa coba modifikasi script yang saya berikan itu nantinya dan coba kembangkan scriptnya.

Dan untuk script lengkapnya, bisa kalian unduh di github saya yang ada dibawah ini:
https://github.com/andspdev/aplikasi-chat-sederhana-nodejs-socketio


Mungkin itu saja tutorial dari saya mengenai cara membuat aplikasi chat sederhana (real time) menggunakan NodeJS dan Socket.io, semoga tutorial yang saya berikan ini dapat bermanfaat bagi kalian semuanya. Jika saya ada salah kata atau salah pengetikkan, saya mohon maaf. Sekian, dan terima kasih.

Selamat Mencoba!

Previous Post Next Post