Build a Real Time Chat App: JS/Express/Socket.IO

Why are you building real time chat apps?

I’m fascinated by the implementations of websockets in different languages and full-duplex communications. I’m building multiple chat apps to explore and sharing my knowledge as I go.

The real time chat app that we are going to build with Socket.IO is the quickest implementation of a real time chat app that I have found so far.

All you need to know how to do is copy and paste to build this.

What's Covered in this Post:

What is Socket.IO?

How to Build a Real Time Chat App

How to Deploy Your App with Heroku


What is Socket.IO?

Socket.IO is a simple JavaScript implementation of websockets to be used in full stack JavaScript web applications. It allows for full-duplex bidirectional server-client communications, just like ActionCable and Phoenix.

See other posts about Real Time Chat Apps: ActionCable implementation & Elixir/Phoenix implementation.

How to Build a Real Time Chat App with Socket.IO

Pre-requisites: installation of Node, npm, git, Macbook, Sublime Text/InsertYourFavoriteTextEditorHere, Internet, basic knowledge of the Terminal

Please go through installating Node before following along with this tutorial.

1) Create a directory called anything you want. This will be where your chat app is stored. Let's call ours `chat-app`.

1a) Run `git init`, `git add .`, and `git commit -m "first message"

2) Create a `package.json` file

Copy and paste the following into your chat-app directory package.json file.

{
  "name": "socket-chat-example",
  "version": "0.0.1",
  "description": "my first socket.io app",
  "dependencies": {}
}

Congratulations! You just made your first package.json file.

2) Run `npm install --save` in your Terminal

This step installs all the files necessary for a node app to run.

3) Run `npm install --save express@4.15.2`.

This installs Express for your app. For more on Express, read the Express docs here.

4) Make an index.js file by running `touch index.js` in your Terminal within your `chat-app` directory

5) Copy and paste the following into `index.js`

var app = require('express')();
var http = require('http').Server(app);

app.get('/', function(req, res){
  res.send('<h1>Hello world</h1>');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

“This translates into the following:

Express initializes app to be a function handler that you can supply to an HTTP server (as seen in line 2). We define a route handler / that gets called when we hit our website home. We make the http server listen on port 3000.”

Socket.IO Chat Docs

6) Run `node index.js` in your Terminal

This starts the node server to render your javascript app. You should see a message that says listening on *:3000 in your Terminal.

7) Go to your browser at the address `http://localhost:3000`

You should see “Hello world”. This means that your app is running successfully locally!

If you have any errors, please review the steps and make sure you are following them in order and typing them exactly into the Terminal and index.js file.

8) Edit your `index.js` file

Copy and paste the following:

app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});

This will replace this code in your index.js file:

app.get('/', function(req, res){
  res.send('<h1>Hello world</h1>');
});

Now, your index.js file should look like this:

var app = require('express')();
var http = require('http').Server(app);

app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});
    

9) Create an `index.html` file by running `touch index.html` in your Terminal within the app root directory

10) Copy and paste the following into your `index.html` file

<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
  </body>
</html>

11) Run `node index.js` in your Terminal

12) Visit your browser at `http://localhost:3000/'

You should see a chat box with a send button in your view now!

13) Install Socket.IO

Run npm install --save socket.io in your Terminal

This will ‘install the module and add the dependency to your package.json‘.

14) Edit your `index.js` to add Socket.IO

Replace all the code in your index.js file with the following:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket){
  console.log('a user connected');
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});

This ‘initialize(s) a new instance of socket.io by passing the http (the HTTP server) object. Then I listen on the connection event for incoming sockets, and I log it to the console.’ Socket.IO Chat Docs

15) Copy and paste the following code right before the end of your `` tag in your `index.html` file

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io();
</script>

16) Run `node index.js` in your Terminal to test out the socket

You should see (in your Terminal) ‘a user connected’. If you refresh the page multiple times, you should see that ‘a user connected’ text each time you refresh.

17) Copy and paste the following into your `index.html`

<script src="/socket.io/socket.io.js"></script>
<script src="https://code.jquery.com/jquery-1.11.1.js"></script>
<script>
  $(function () {
    var socket = io();
    $('form').submit(function(){
      socket.emit('chat message', $('#m').val());
      $('#m').val('');
      return false;
    });
  });
</script>

This should replace the previous code

<script src="/socket.io/socket.io.js"></script>
<script>
  var socket = io();
</script>

So, now your index.html should look like this:

<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://code.jquery.com/jquery-1.11.1.js"></script>
    <script>
      $(function () {
        var socket = io();
        $('form').submit(function(){
          socket.emit('chat message', $('#m').val());
          $('#m').val('');
          return false;
        });
      });
    </script>
  </body>
</html>

18) Copy and paste the following into your `index.js` file

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    console.log('message: ' + msg);
  });
});

Now, your index.js file should look like this:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    console.log('message: ' + msg);
  });
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});
    

19) Run `node index.js` in your Terminal & Visit `http://localhost:3000/`

If you type into your text box on the screen, then click ‘Send’. Check your terminal. You should see something like

message: asdf

Where your message is ‘asdf’. Type in whatever you want and it will show up in the Terminal! Give it a try!

20) Copy and paste the following into `index.js`

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});

So, your index.js file should look like this:

var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);

app.get('/', function(req, res){
  res.sendFile(__dirname + '/index.html');
});

io.on('connection', function(socket){
  socket.on('chat message', function(msg){
    io.emit('chat message', msg);
  });
});

http.listen(3000, function(){
  console.log('listening on *:3000');
});
    

21) Copy and paste the following into `index.html`

<script>
  $(function () {
    var socket = io();
    $('form').submit(function(){
      socket.emit('chat message', $('#m').val());
      $('#m').val('');
      return false;
    });
    socket.on('chat message', function(msg){
      $('#messages').append($('<li>').text(msg));
    });
  });
</script>

So your index.html page should look like this now:

<!doctype html>
<html>
  <head>
    <title>Socket.IO chat</title>
    <style>
      * { margin: 0; padding: 0; box-sizing: border-box; }
      body { font: 13px Helvetica, Arial; }
      form { background: #000; padding: 3px; position: fixed; bottom: 0; width: 100%; }
      form input { border: 0; padding: 10px; width: 90%; margin-right: .5%; }
      form button { width: 9%; background: rgb(130, 224, 255); border: none; padding: 10px; }
      #messages { list-style-type: none; margin: 0; padding: 0; }
      #messages li { padding: 5px 10px; }
      #messages li:nth-child(odd) { background: #eee; }
    </style>
  </head>
  <body>
    <ul id="messages"></ul>
    <form action="">
      <input id="m" autocomplete="off" /><button>Send</button>
    </form>
    <script src="/socket.io/socket.io.js"></script>
    <script src="https://code.jquery.com/jquery-1.11.1.js"></script>
    <script>
  $(function () {
    var socket = io();
    $('form').submit(function(){
      socket.emit('chat message', $('#m').val());
      $('#m').val('');
      return false;
    });
    socket.on('chat message', function(msg){
      $('#messages').append($('<li>').text(msg));
    });
  });
</script>
  </body>
</html>

22) Run `git add .` and `git commit -m "finished real time chat app` in your Terminal

Congratulations!

You just built a Real Time Chat App with Socket.IO and Express in JavaScript that runs locally!

Find the code on GitHub

Deploying Your Real Time App to Heroku

Pre-requisites: install Heroku CLI + same pre-reqs as before

1) Run `heroku create` in your Terminal inside your `chat-app` directory

You should see something like

Creating app... done, ⬢ damp-everglades-14640
https://{your-app-name-here}.herokuapp.com/ | https://git.heroku.com/{your-app-name-here}.git

Run git remote -v to check that you have a remote Heroku branch.

2) Edit app to set the port dynamically in your `index.js` file
Copy and paste: 
http.listen(process.env.PORT || 3000, function(){
  console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});

(Adapted from StackOverflow - Deploy Error H10 for Heroku)

3) Edit the `package.json` file to include a "start" script

"scripts": {
    "start": "node your-script.js"
}

4) Run `git add .` && `git commit -m "finished deployment config"` and `git push heroku master` to deploy

Congratulations! You're done! You've deployed!

Check out your app at your heroku location. ( http://{your-app-name}.herokuapp.com/)

Real Time Chat App

If you have any errors, try to debug them by running heroku logs in your Terminal or seeing any errors in your console.log or debugger in JavaScript or running it locally with npm start to see any errors. If you need to, feel free to reach out to me personally for help, @maxxgrok.

Thanks for reading this post!

Published 13 Jun 2018

founder && full stack && ethereum developer.
Max Goodman on Twitter