Browser Web Chat in 5 minutes

About

This mini-project shows how to implement a simple web browser chat utilizing websockets technology for bi-directional client to server communication.
We are using node.js, express and socket.io for the implementation.

Live coding

Here is a live coding session that shows how it can be done.

Duration: 4:08 (coding - 3:51)

Disclaimer: never use this code in production. It was created for fun.

Breakdown

Let's break down the solution and comment on some complex or interesting things.

0:13 - initialization of the project. Every node.js-based project starts with package.json file that contains all dependencies, run scripts and many more. npm init -y command just creates minimal package.json file inside current folder.

0:19 - installing dependencies. For the project we need only 2 of them - express and socket.io. Using --save parameter to make sure that these dependencies find their place in package.json. After this step package.json should look like this:

{
    "name": "webchat",
    "version": "1.0.0",
    "description": "",
    "main": "index.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {
        "express": "^4.17.1",
        "socket.io": "^4.3.0"
    }
}    
Note that the versions might differ - new versions are released quite frequently.

0:33 - building basic HTML template.

0:45 - starting work on server side. We will be using express as a framework for building the web server.
On this step the server does not do anything much than just serving the static content from the current folder.
The server will be running on port 3000 - there is no specific logic behind this port number. But somehow it's popular withing express world.

1:07 - run the server with node index.js. Our project is very simple and does not require any build or assembly pipeline. Server is only one file that can be run directly by node.js engine.
In more complex scenarios the run script should be described inside package.json.
Exprected result at this step - web server running on port 3000 serves static content (index.html file) from current folder.

1:15 - adding layout to HTML page. The UI is very simple and minimalistic. It will contain single input field for chat message, "Send" button and an area for the received messages. No formatting, no styles, no emoji - just plain HTML page.

1:30 - activating websockets on the server side. For this we use socket.io that can hook up to existing express server.
socket.io is an event-based framework - we'll write code that reacts to certain events. For the start we are interested in handling of new connections - when a new client opens a websocket connection to the server.
Note that we can use socket parameter of connection event later on - it represents the particular client.

1:50 - switching back to the web page development. We need to use the websockets client in the HTML page. Easiest way is to use the client that comes with server-side socket.io.
In the beginning we ran npm i --save express socket.io command that downloaded required dependencies and stored them in node_modules folder. Here we are cutting the corner and just using a client from locally installed package.
In real life the websockets client should be separated and stored locally next to the client.

1:57 - initialization code for websockets client. Just create socket.io client and that's all for the minimalistic setup.
Also for fun let's make every client unique and assign every brower client a random name.
Here we handle successful connection as well - once the connection is established we can communicate with the server. In our case we just notifying the server that new user has joined.
Right now there is nothing on the backed related to new client's joining - but we'll address it a bit later.
But already now (after browser refresh) we see messages in server console that new client is there.

2:22 - the remaining part for the frontend is sending and receiving messages. Here we need to work with a couple of HTML elements:


We can attach onsubmit event handler to the form. Notice that we are doing e.preventDefault(); not to propagate submit event - otherwise it will be considered as POST action on the page and the browser window will be reloaded.
Sending a message to the chat is done using socket.emit call - later it will be handled on server side.
Receiving a message (or any other update from the server) is done using socket.on. The callback function will be called every time when new message arrives.
As it is minimalistic setup we don't care much about security here. As result our chat is vulnerable against various attacks, for example, XSS (cross site scripting). To prove it, just submit <b>bold text goes here</b>. The received message will be rendered with HTML formatting.

3:05 - finishing off with server side implementation. We need to handle these scenarios:


Remember on the frontend side we had implementation to emit joined event when the websocket connection is established. We need to handle this event using socket.on to receive user name.
Sending of the message to everyone is done using io.emit. Notice that if we do socket.emit then the message will be send only to current user, not to everyone.
Resending the message to all people is also done using io.emit

This concludes this mini-project. It looks very simple due to power of used libraries (express and socket.io) as they hide all complexity.

Resources

Sources: https://github.com/5minute/examples/tree/main/webchat