In this tutorial, we'll make a chat app with a difference. Instead of the usual web client to server chat architecture, we'll have a chat app directly running from your repl's console window in Replit.
We'll use Socket.io to implement websockets in our app. We're helped by the fact that the Socket.io-client code can be run in Node.js, not only in a browser!
Overview and Requirements
We'll use the Replit web IDE for developing and running our chat app. We will end up with one Replit project that runs the chat server, and as many client Replit projects as you want to chat between. You'll need a Replit account for this tutorial, so create an account if you haven't already.
In this tutorial, we will:
- Create the chat server using Express and Socket.io.
- Create a chat client using the Socket.io-client.
- Use the readline module in Node.js to create the user interface to chat from your repl's console window.
Create a Chat Server
- Log into Replit and create a new repl.
- Choose Node.js as your language.
- Name your repl something like "repl-chat-server".
Add a web framework
We need to start with a web framework that will be able to route incoming requests from chat clients. We'll use Express, a popular Node.js web framework. In the default index.js
file, add a reference to expressjs and create a new express app:
const express = require('express');
const app = express();
Replit has a super useful package feature which means we don't need to manually install packages. They will be installed automatically when we reference them in the code, as we've done for Express.
Add a web server
Now that we have a web framework to route our requests, we need to create a web server to listen for requests and handle the HTTP protocol. We will use the built in node HTTP module for this.
Add a reference to HTTP, and create a new server with the express framework we created above:
const http = require('http');
const server = http.Server(app);
Extend the server with Socket.io
To make the chat responsive in realtime, we are going to extend our web server with websockets. Websockets are used to create a long-lived connection between clients and servers. This means we don't have the overhead of creating a new connection to the server each time we want to send and receive messages. Talk about efficient!
Add the following code to extend your server to support websockets:
const sockets = require('socket.io');
io = sockets(server);
Listen for new connections and messages
Now that we've got all our infrastructure, we can set up how we want to handle new connections and messages. Socket.io has many events that we can create and listen for. We'll be using the new connection
event and a custom message
event. Add the following code to handle new connection events and incoming messages from clients:
io.on('connection', function (connection) {
connection.on('message', function(data) {
console.log('new message: ' + data);
io.emit("broadcast", data);
});
});
This code handles a new connection event on line 1. It grabs this connection, and waits for a new message to be sent by the client on line 2.
Once it has a new message, it writes it to the local server console on line 3. This is really just for our own debugging and interest. In a production application, perhaps we would save the message logs for later browsing.
Line 4 is where we send out, or emit, the incoming message to all connected clients, so they can see the message.
Start up and test the server
Finally, we need to start up our chat server to listen for connections. Add this code to start the server:
server.listen(3000, function() {
console.log('listening on port 3000');
});
To test the server, click the big "Run" button at the top of your repl. You should see it installing packages, output the connection, and finally write listening on port 3000.
Complete server code
The server code is done! Your completed code should look like this:
const express = require('express');
const app = express();
const http = require('http');
const server = http.Server(app);
const sockets = require('socket.io');
io = sockets(server);
io.on('connection', function (connection) {
connection.on('message', function(data) {
console.log('new message: ' + data);
io.emit("broadcast", data);
});
});
server.listen(3000, function() {
console.log('listening on 3000');
});
Building the Chat Client
Create a new repl with Node.js as the chosen language. Give this repl a name, like "repl-chat-client".
Add the Socket client and readline modules
Add the Socket.io-client and readline module to the index.js file:
const io = require('socket.io-client');
const readline = require('readline');
Create a new connection to the chat server
Add a connection to your chat server repl by adding the line:
var socket = io("https://repl-chat-server.<your username>.repl.co");
Replace <your username>
in the line above with your actual Replit username.
Setup a console interface
Because we are creating this chat app purely in the repl console, we need to be able to read and write messages from the console. To help us do this, we'll use the readline module. Create the interface by adding this code:
const chat_interface = readline.createInterface({
input: process.stdin,
output: process.stdout
});
The line input: process.stdin
means that we will be getting user input from the Standard Input, which commonly means the console. Likewise, output: process.stdout
means we will output messages to the Standard Output, i.e. the console.
User and message variables
To remember the user's chat handle (username) and the message they want to send, we'll set up two variables. Add this to your code:
var chat_handle = "";
var message_to_send = "";
Handle Socket events
We are interested in two main events:
- When we successfully connect to the chat server.
- When the server broadcasts messages to us.
Add this code to connect to these events:
socket.on('connect', function(){
get_chat_handle();
socket.on('broadcast', display_message);
});
You'll notice this code calls two methods: get_chat_handle
and display_message
. We'll define these next.
Getting the user chat handle
Once we're successfully connected to the server, we'll want to introduce the user. Add this function to your code:
// Gets the user's name, so we can introduce and prepend each message with their name
function get_chat_handle(){
chat_interface.question(`Hello! What's your chat handle? `, function(answer){
chat_handle = answer;
socket.emit("message", chat_handle + ' has entered the chat');
chat();
});
}
This uses the interface we set up earlier to ask a question to the user: "What's your chat handle?". When we get the answer, we store it in the variable chat_handle
that we added earlier. We then send this to the server using socket.emit("message")
. The server will get the message, and then broadcast it to all the other chat clients.
Finally, we call the chat()
function, which we will set up next.
Waiting and sending user messages
Now we'll implement the chat()
function, which waits for a user's message and sends it to the server. Add this function to your code:
// Waits for a new message to send
function chat(){
chat_interface.question(chat_handle + ": ", function(message){
message_to_send = chat_handle + ': ' + message;
socket.emit("message", message_to_send );
chat();
});
}
This code adds a prompt to the console with the user's chat_handle
, and waits for them to enter a message. This is done through the chat_interface.question
method. When they enter a message, we prepend it with the user's chat handle and save it to the variable message_to_send
that we added earlier. Then we send this combined user chat handle and message to the server using socket.emit
. Finally, we call our chat()
function again, to set up a prompt and wait for the next message.
Showing messages from other users
Our last function writes out messages that we receive from the server. We get these messages in this code we added earlier: socket.on('broadcast', display_message);
This code listened for any broadcast message, and then called the function display_message
. We'll implement this function now.
Add the display_message
function to your code:
// Handles an incoming message, and checks to see that it is not the one we sent.
// Shows it on the console if it is from another user.
function display_message(message){
if(message_to_send != message){
console.log("\n" + message);
chat();
}
}
As noted in the comment above the function declaration, this function first compares the incoming message to the last message the user sent, stored in the message_to_send
variable. If the incoming message matches, the function ignores it and doesn't write it out. It would look pretty weird if a user sent a message, and then had it sent right back to them!
If it doesn't match (i.e it is a message from another user), then we write it to the console with a newline \n
preceding it. Then we wait for our user to send a reply by calling our chat()
function again.
Complete client code
We are done with the chat client code! The completed code should look like this:
const io = require('socket.io-client');
const readline = require('readline');
var socket = io("https://repl-chat-server.<your username>.repl.co");
const chat_interface = readline.createInterface({
input: process.stdin,
output: process.stdout
});
var chat_handle = "";
var message_to_send = "";
socket.on('connect', function(){
get_chat_handle();
socket.on('broadcast', display_message);
});
// Gets the user's name, so we can introduce and append each message with their name
function get_chat_handle(){
chat_interface.question(`Hello! What's your chat handle? `, function(answer){
chat_handle = answer;
socket.emit("message", chat_handle + ' has entered the chat');
chat();
});
}
// Waits for a new message to send
function chat(){
chat_interface.question(chat_handle + ": ", function(message){
message_to_send = chat_handle + ': ' + message;
socket.emit("message", message_to_send );
chat();
});
}
// Handles an incoming message, and checks to see that it is not the one we sent.
// Shows it on the console if it is from another user.
function display_message(message){
if(message_to_send != message){
console.log("\n" + message);
chat();
}
}
Remember to replace <your username>
in the Socket connection with your actual username on Replit!
Running the client app
Now you can click the "Run" button at the top of the chat client repl to test the client app. You should see it installing packages, output the connection, and finally ask Hello! What's your chat handle?.
This assumes you are still running the chat server we created earlier.
If you type in a message to your client, you should see it logged on the server. The image below shows the repl console of the client on the left, and the repl console of the server on the right.
Chatting With a Friend
Now that we've built a server and a client, we can chat with a buddy. Get a friend to copy the client code and run it in their own Replit account so that they can chat with you. Alternatively, share a link with them to your chat client repl.
Run the chat server app. Then run your client app, and your friend's client app.
You should see the client apps prompt for your usernames. After you send them, they'll be shown on both clients and in the server logs. Now you can message each other from the repl console! Once you're comfortable that it works with a friend, you can invite others to join, too.
Make it Your Own
If you followed along, you'll already have your own version of the chat server and chat client repl to extend. If not, start from ours. Fork the chat server or chat client from the repls embedded below.
Example repls
You can find our example repls of the
Chat server and chat client
Things to Try Next
You can try some interesting things to spice up your chat app.
- Try using different colors on the message outputs – one for the user, and another for their chat friends. There are many modules available for this, one of them being colors.
- Try logging the server messages to the Replit database, so that you can restore previous chats.
Top comments (0)