DEV Community

EneasLari
EneasLari

Posted on • Edited on • Originally published at eneaslari.com

How to Create a Chat App With Bun Using WebSockets

Lets Create a Bun Server

bun init

Just press enter.. enter..

bun1

Run the file

bun run index.ts`
Enter fullscreen mode Exit fullscreen mode

Implementing WebSockets in JavaScript

Let’s create a simple WebSocket connection in JavaScript. Firstly, ensure your server supports WebSocket connections.

// Creating a new WebSocket instance
const socket = new WebSocket('ws://your-websocket-server.com');

// Connection opened
socket.addEventListener('open', (event) => {
    socket.send('Hello Server!');
});

// Listen for messages
socket.addEventListener('message', (event) => {
    console.log('Message from server:', event.data);
});

// Connection closed
socket.addEventListener('close', (event) => {
    console.log('Server connection closed:', event.data);
});
Enter fullscreen mode Exit fullscreen mode

In this snippet:

  1. We create a new WebSocket instance, passing the WebSocket server URL.
  2. We attach an event listener for the open event, which triggers when the connection is established, sending a greeting to the server.
  3. We listen for any messages from the server with the message event.
  4. Finally, we have a listener for the close event, which triggers when the connection is closed.

Let's Build a simple WebSocket server with Bun

First rename index.ts to server.ts

index.ts

const server = Bun.serve({
    port: 8080,
    fetch(req, server) {
        // upgrade the request to a WebSocket
        if (server.upgrade(req)) {
            return; // do not return a Response
        } 
        return new Response("Upgrade failed :(", { status: 500 });
    }, // upgrade logic
    websocket: {
        async message(ws, message) {
            console.log("Message was received from server:",message)
            ws.send("I received your message")
        }, // a message is received
        open(ws) {
            console.log("Connection opened")
        }, // a socket is opened
        close(ws, code, message) {
            console.log("Connection closed")
        }, // a socket is closed
        drain(ws) {}, // the socket is ready to receive more data
    },
  });

  console.log(`Listening on ${server.hostname}:${server.port}`);
Enter fullscreen mode Exit fullscreen mode

Now, to start your server, run the following command in the terminal:

bun run server.ts
Enter fullscreen mode Exit fullscreen mode

Creating Chat Room

First let's create a client's UI (a html page)

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>WebSocket client</title>
  </head>
  <body>
    <button id="sendmessagebutton">Broadcast Message</button>
    <button id="sendtoserver">Send Message to server</button>
    <p id="logging">Logging:</p>
    <script src="client.js"></script>
  </body>
</html>

Enter fullscreen mode Exit fullscreen mode
  • The "Broadcast Message" button is for sending a message for broadcasting
  • The "Send message to server" is for sending message only to server
  • The paragraph is for logging things on the client

Now let's change a little bit the client.js

// Creating a new WebSocket instance
const socket = new WebSocket('ws://localhost:8080');

// Connection opened
socket.addEventListener('open', (event) => {
    var sayhi = {
        "type": "SENDTOSERVER",
        "payload": {
            "message": "Hello server, How are you?"
        }
    }
    socket.send(JSON.stringify(sayhi));
    document.getElementById("logging").innerText += "\n" + "You sent this mesage to the server: " + sayhi.payload.message

    document.getElementById("sendmessagebutton").addEventListener("click", () => {
        var newmessage = {
            "type": "BROADCAST",
            "payload": {
                "author": "A USER",
                "message": "Hi everyone!"
            }
        }
        socket.send(JSON.stringify(newmessage))
        document.getElementById("logging").innerText += "\n" + "You sent this mesage for broadcasting to the server: " + newmessage.payload.message
    })
    document.getElementById("sendtoserver").addEventListener("click", () => {
        var newmessage = {
            "type": "SENDTOSERVER",
            "payload": {
                "author": "A USER",
                "message": "This message is for server only"
            }
        }
        socket.send(JSON.stringify(newmessage))
    })
});

// Listen for messages
socket.addEventListener('message', (event) => {
    try {
        var message = JSON.parse(event.data);
        if (message.type === 'BROADCAST') {
            document.getElementById("logging").innerText += "\n" + "A client broadcasted: " + message.payload.message
        } else {
            document.getElementById("logging").innerText += "\n" + "You received this message: " + message.payload.message
        }

    } catch (e) {
        console.log('Wrong format');
        return;
    }
});

// Connection closed
socket.addEventListener('close', (event) => {
    console.log('Server connection closed:', event.data);
});
Enter fullscreen mode Exit fullscreen mode

We will change the server so it can differentiate the messages that are for broadcasting and for server only.

const wsserver = Bun.serve({
    port: 8080,
    fetch(req, server) {
        // upgrade the request to a WebSocket
        if (server.upgrade(req)) {
            return; // do not return a Response
        }
        return new Response("Upgrade failed :(", { status: 500 });
    }, // upgrade logic
    websocket: {
        async message(ws, msg) {
            console.log("Message was received from server:", msg)
            var message;
            try {
                message = JSON.parse(msg.toString());

            } catch (e) {
                console.log('Wrong format');
                return;
            }

            if (message.type === 'BROADCAST') {
                // Broadcast the message to all connected clients
                var newmessage = {
                    "type": "BROADCAST",
                    "payload": {
                        "author": "Server",
                        "message": message.payload.message
                    }
                }
                ws.publish("chat",JSON.stringify(newmessage))
            }
            if (message.type === 'SENDTOSERVER') {
                var respond = {
                    "type": "SERVER_MESSAGE",
                    "payload": {
                        "author": "Server",
                        "message": "I received your message:<<" + message.payload.message + ">>"
                    }
                }
                ws.send(JSON.stringify(respond));
            }




        }, // a message is received
        async open(ws) {
            ws.subscribe("chat")
            console.log("Connection opened and you subscribed on chat")
        }, // a socket is opened
        async close(ws, code, message) {
            console.log("Connection closed")
        }, // a socket is closed
        async drain(ws) { }, // the socket is ready to receive more data
    },
});

console.log(`Listening on ${wsserver.hostname}:${wsserver.port}`);
Enter fullscreen mode Exit fullscreen mode

Let's test things:

run node server.js

Then press the Go Live button on visual studio code to fire up a client

websocket

You should see this:

websocket

If you open a second tab you will connect a second client:

websocket

Then you can broadcast messages(press "Broadcast Message")
The server will receive the message and will broadcast it to the clients (except sender)

websocket

Also, you can send messages only to the server and get a response

websocket

That's for now!

You can find the code of this article here : GitHub Repository

Sources

bun.sh Set per-socket contextual data on a WebSocket with Bun

bun.sh WebSockets

bun.sh Build a simple WebSocket server with Bun

Create a chat application with Bun JavaScript runtime

Top comments (1)

Collapse
 
grenishrai profile image
Grenish rai

That is really nice knowing how you use bunjs. Really appreciate it.