Using socket.io in Express 4 and express-generator's /bin/www

Javascriptnode.jsExpresssocket.io

Javascript Problem Overview


So here is the deal: I'm trying to use socket.io in an express project. After Express Js 4 was lauched, i've updated my express-generator and now the app initial functions goes into ./bin/www file, including those vars (www file contents: http://jsfiddle.net/avMa5/ )

var server = app.listen(app.get('port'), function() {..}

(check it by npm install -g express-generator and then express myApp

that being said, let's remember how socket.io docs ask us to fire it:

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

Ok but i can't do it inside app.js, like recommended. This should be done in ./bin/www in order to work. in ./bin/www this is what i can do to get it working:

var io = require('socket.io')(server)

Ok this works, but i can't use the io var anywhere else, and i really don't want to put my socket.io functions on www file.

I guess this is just basic syntax, but I can't get this to work, not even using module.exports = server or server.exports = server nor module.exports.io = app(io) on www file

So the question is: how can i use socket.io having this /bin/www file as starting point of my app?

Javascript Solutions


Solution 1 - Javascript

Here is how you can add Socket.io to a newly generated Express-Generator application:

  1. Create a file that will contain your socket.io logic, for example socketapi.js:

socketapi.js:

const io = require( "socket.io" )();
const socketapi = {
    io: io
};

// Add your socket.io logic here!
io.on( "connection", function( socket ) {
    console.log( "A user connected" );
});
// end of socket.io logic

module.exports = socketapi;

2. Modify your bin/www launcher. There are two steps: requiring your Socket.io api and attaching the HTTP server to your socket.io instance right after creating the HTTP server:

bin/www:

/**
 * Module dependencies.
 */

var app = require('../app');
var debug = require('debug')('socketexpress:server');
var http = require('http');
let socketapi = require("../socketapi"); // <== Add this line

/**
 * Get port from environment and store in Express.
 */

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

/**
 * Create HTTP server.
 */

var server = http.createServer(app);
socketapi.io.attach(server); // <== Also add this line

(...)

3. Then you just need to add the Socket.io client in your index.html. Add the following just before the </body> closing tag:

index.html

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

4. Finally you can start your Express server:

  • Unix based: DEBUG=myapp:* npm start
  • Windows: set DEBUG=myapp:* & npm start

Note 1

If for any reason you need access to your socket api in your app.js, then you could instead import your socket api in app.js, and re-export it:

app.js

var express = require('express');
var socketapi = require("./socketapi"); // <== Add this line
(...)
// You can now access socket.io through the socketapi.io object
(...)
module.exports = { app, socketapi }; // <== Export your app and re-export your socket API here

Then in your bin/www launcher, instead of importing your socket api on its own line, just import it along your app:

bin/www

var {app, socketapi} = require('../app'); // <== Import your app and socket api like this
(...)
var server = http.createServer(app);
socketapi.io.attach(server); // <== You still have to attach your HTTP server to your socket.io instance

Note 2 This answer was updated to work with the latest Express Generator (4.16 at time of writing) and latest Socket.io (3.0.5 at time of writing).

Solution 2 - Javascript

A little different approach to initiate socket.io, it groups all related code in one place:

bin/www

/**
 * Socket.io
 */
var socketApi = require('../socketApi');
var io = socketApi.io;
io.attach(server);

socketApi.js

var socket_io = require('socket.io');
var io = socket_io();
var socketApi = {};

socketApi.io = io;

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

socketApi.sendNotification = function() {
    io.sockets.emit('hello', {msg: 'Hello World!'});
}

module.exports = socketApi;

app.js

// Nothing here

In this way all socket.io related code in one module and function from it I can invoke from anywhere in application.

Solution 3 - Javascript

It turns out it really was some basic sintax problem.... I got these lines from http://chariotsolutions.com/blog/post/getting-chatty-angular-socket-io-nodeexpress-bootstrap/"> this socket.io chat tutorial...

on ./bin/www, just after var server = app.listen(.....)

var io = require('socket.io').listen(server);
require('../sockets/base')(io);

so now I create the ../sockets/base.js file and put this little fellow inside it:

module.exports = function (io) { // io stuff here... io.on('conection..... }

Yeah! Now it works... So i guess i really had no option other than starting socket.io inside /bin/www , because that is where my http server was started. The goal is that now i can build socket functionality in other file(s), keeping the thing modular, by require('fileHere')(io);

<3

Solution 4 - Javascript

The old "expressjs", everything is happening in the file "app.js". So the socket.io binding to server also happens in that file. (BTW, one can still do it the old way, and remove bin/www)

Now with the new expressjs, it needs to happen in the "bin/www" file.

Fortunately, javascript/requirejs made it easy to pass objects around. As Gabriel Hautclocq pointed out, socket.io is still "imported" in "app.js" and it gets attached to "app" object via a property

app.io = require('socket.io')();

The socket.io is made live by attaching to it the server in "bin/www"

app.io.attach(server); 

because "app" object is passed into "bin/www" earlier

app = require("../app");

It's really just as simple as

require('socket.io')().attach(server);

But doing it the "difficult" way ensures that app.io now holds the socke.io object.

Now if you need this socket.io object also in "routes/index.js" for example, just use the same principle to pass that object around.

First in "app.js", do

app.use('/', require('./routes/index')(app.io));

Then in "routes/index.js"

module.exports = function(io){
    //now you can use io.emit() in this file

    var router = express.Router();



    return router;
 }

So "io" gets injected into "index.js".

Solution 5 - Javascript

Update to Gabriel Hautclocq's response:

In www file, the code should appear as the following due to updates with Socket.io. Attach is now Listen.

/**
 * Create HTTP server.
 */
 
var server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', onError);
server.on('listening', onListening);


/**
 * Socket.io
 */
var io = app.io;
io.listen(server);`

Additionally getting that connection to work requires implementing the client side API as well. This isn't Express specific but without it the connect call won't work. The API is included in

/node_modules/socket.io-client/socket.io.js. 

Include this file on the front end and test with the following:

var socket = io.connect('http://localhost:3000');

Solution 6 - Javascript

After reading through all of the comments, I came up with the following using Socket.io Server Version: 1.5.0

Issues that I ran into:

  1. var sockIO = require('socket.io') should be var sockIO = require('socket.io')(). (Credit to: Zhe Hu)

  2. sockIO.attach should be sockIO.listen (Credit to: rickrizzo)

Steps

  1. Install Socket.io with the following command:

     npm install --save socket.io
    
  2. Add the following to app.js:

     var sockIO = require('socket.io')();
     app.sockIO = sockIO;
    
  3. In bin/www, after var server = http.createServer(app), add the following:

     var sockIO = app.sockIO;
     sockIO.listen(server);
    
  4. To test functionality, in app.js, you can add the line:

     sockIO.on('connection', function(socket){
         console.log('A client connection occurred!');
     });
    

Solution 7 - Javascript

A tutorial for beginners from Cedric Pabst
here are the short basics form the link for an app chat:

using express-generate and the ejs engine usable in every .ejs file standard routing in express-generate

edit the file bin\www and add this app.io.attach(server); like this

...
/*
 * Create HTTP server.
/*  
var server = http.createServer(app);
/*
 * attach socket.io
/*  
app.io.attach(server); 
/*
 * Listen to provided port, on all network interfaces.
/*  
...

edit in app.js

//connect socket.io
... var app = express();
// call socket.io to the app
app.io = require('socket.io')();

//view engine setup
app.set('views', path.join(_dirname, 'views'));
...



...
//start listen with socket.io
app.io.on('connection', function(socket){
console.log('a user connected');

// receive from client (index.ejs) with socket.on
socket.on('new message', function(msg){
      console.log('new message: ' + msg);
      // send to client (index.ejs) with app.io.emit
      // here it reacts direct after receiving a message from the client
      app.io.emit('chat message' , msg);
      });
});
...
module.exports = app;

edit in index.ejs

 <head>  
   <title><%= title %></title>
   <link rel='stylesheet' href='/stylesheets/style.css' />
   <script src="/socket.io/socket.io.js"></script>
   //include jquery
   <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
   <script>
   var socket = io();
   //define functions socket.emit sending to server (app.js) and socket.on receiving 
     // 'new message' is for the id of the socket and $('#new-message') is for the button
     function sendFunction() {
     socket.emit('new message', $('#new-message').val());
     $('#new-message').val('');
   }
    // 'chat message' is for the id of the socket and $('#new-area') is for the text area
   socket.on('chat message', function(msg){
     $('#messages-area').append($('<li>').text(msg));
   });
   </script>
 </head>  
 
 <body>  
   <h1><%= title %></h1>
   <h3>Welcome to <%= title %></h3>
   <ul id="messages-area"></ul>
   <form id="form" onsubmit="return false;">
     <input id="new-message" type="text" /><button onclick="sendFunction()">Send</button>
   </form>
 </body>

Have fun :) and thanks many to Cedric Pabst

Solution 8 - Javascript

Some previous answers are not working and others are overly complicated. Try the following solution instead...

Install server-side and client-side socket.io node modules:

npm install --save socket.io socket.io-client
Server-side

Add the following code to bin/www after the server definition, var server = http.createServer(app);:

/**
 * Socket.io
 */

var io = require('socket.io')(server);

io.on("connection", function(socket){
  console.log("SOCKET SERVER CONNECTION");
  socket.emit('news', { hello: 'world' });
});
Client-side

If using webpack, add the following code to your webpack entry.js file:

var socket = require('socket.io-client')();
socket.on('connect', function(){
  console.log("SOCKET CLIENT CONNECT")
});

socket.on('news', function(data){
  console.log("SOCKET CLIENT NEWS", data)
});

Done. Visit your site and check the browser's js developer console.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser1576978View Question on Stackoverflow
Solution 1 - JavascriptGabriel HautclocqView Answer on Stackoverflow
Solution 2 - JavascriptAnatolyView Answer on Stackoverflow
Solution 3 - Javascriptuser1576978View Answer on Stackoverflow
Solution 4 - JavascriptZhe HuView Answer on Stackoverflow
Solution 5 - JavascriptrickrizzoView Answer on Stackoverflow
Solution 6 - JavascriptBrianView Answer on Stackoverflow
Solution 7 - JavascriptAnnaBananaView Answer on Stackoverflow
Solution 8 - Javascripts2t2View Answer on Stackoverflow