Using socket.io in Express 4 and express-generator's /bin/www
It turns out it really was some basic sintax problem.... I got these lines from 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
Using socket.io with express 4 generator
I have to say, I think the default generated project is bad for a socket.io setup. The node http.Server var is all the way in bin/www
and not in app.js
.
So the first thing is to move all the relevant stuff from bin/www
to app.js
. Mainly you just need
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
just like in the socket.io docs.
Now with io
in app.js
, we can use that when the routes are required. I forgot how exactly the default routes are set up, but I think they set up an app
and just export it. Instead, you can set up something like
module.exports = function(app, io) {
io.on('connection', function(socket) {
console.log('connected!');
}
app.get('/foo', function() {
...
}
}
And now when you require the routes, instead of having the default
var index = require('./routes/index');
app.use(index);
or something of that accord, you can just do
require('./routes/index')(app, io);
And that's how you get io
into your routes. Or at least how I do it anyway.
Express-Generator - Including socket.io (bin/www)
Its typical to require socket.io in app.js and then to tell your io sever to listen to your application. Using the example you posted, that would look like this:
var debug = require('debug')('rhubarb');
var app = require('../app');
var server = require('http').Server(app);
var io = require('socket.io')(server);
app.set('port', process.env.PORT || 1127);
var server = server.listen(app.get('port'), function() {
debug('Express server listening on port ' + server.address().port);
});
The socketio docs do a really good job of explaining this. Here's an example from their homepage:
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
server.listen(80);
app.get('/', function (req, res) {
res.sendfile(__dirname + '/index.html');
});
io.on('connection', function (socket) {
socket.emit('news', { hello: 'world' });
socket.on('my other event', function (data) {
console.log(data);
});
});
Update:
I typically modularize socketio setup by creating a lib called io.js in /lib
with something like this:
module.exports = function(server){
var io = require('socket.io')(server);
// catch errors
io.on('error', function(err){
throw err;
})
// Set Socket.io listeners by creating a socket.io middleware
// attachEventlisteners would live in `/controllers`
io.use(attachEventlisteners);
io.on('connection', function (socket) {
// do things
});
return io; // so it can be used in app.js ( if need be )
}
then in app.js i can simply pass the server
in when I require it:
var io = require('./lib/io')(server);
You dont need to do any thing further in app.js since everything is setup in /lib/io.js
, but if you wanted to you could because the io server is returned.
Node.js Express 4 Generator with Mutliple Socket.io files
You're overwriting app.io each time. app.io = require('./socket.io/file1');
isn't "calling socket.io" but assigns app.io to that module. There are multiple ways to solve this, for example:
in app.js:
app.io = [
require('./socket.io/file1'),
require('./socket.io/file2'),
require('./socket.io/file3')
]
in /bin/www:
app.io.forEach(function (socketIo) {
socketIo.attach(server);
});
This assigns an array to app.io and /bin/www iterates over the array to attach the server to each socket.io instance.
I couldn't test if this works and i suspect it doesn't (I wrote it just to illustrate the first problem in your code). I think one can use only a single socket.io instance per http server. But there is a solution:
tl;dr
Use socket.io namespaces. Create a single instance of socket.io and attach it to the server like you already do, then create "submodules" via io.of("/module-name")
in each of your module files (like file1, etc). Please read the documentation to learn more about namespaces.
Update:
There are again multiple options to do that, e.g.: (Warning, code is from one of my own codebases, and is originally written in coffee-script and translated in my head, but you should get the gist)
in io.coffee
var io = require('socket.io')(http)
require('./broadcast.coffee')(io)
require('./livelog.coffee')(io)
Where http is, of course, your http server instance.
in broadcast.coffee
module.exports = function (io) {
var broadcast = io.of('/broadcast')
broadcast.on('connection', function (socket) {
socket.emit('foo', 'bar')
})
}
socket.io with express generator
in app.js you have this code:
var messages = require('./routes/messages')(io);
var app = express();
// socket.io
var io = socket();
app.io = io;
You should initialize io variable before passing it to messages export function - like so:
var app = express();
// socket.io
var io = socket();
app.io = io;
var messages = require('./routes/messages')(io);
Socket.io and Express 4
For your first two questions, I believe this post will help you with that Using socket.io in Express 4 and express-generator's /bin/www
As for your last question, you should put the relevant socket.io logic within the file of where it's needed. It definitely should not all be stored in one place. In the chat example of socket.io, you'll notice that they separate the socket.io logic from when you send a message to when you receive one.
Configure socket.io with node express generator
First, let me tell you, what you're trying to do is kinda right. Not to mess with the bin/www
would be fine.
But remember express generator is just that. A generator for you to build upon. You generate, and the apply your own modifications.
My choice would be to:
- copy
bin/www
to a newbin/wwwio
, - Update the
bin/wwwio
script to attach socket.io to the created http server. - Update
bin/wwwio
torequire()
a new file../io.js
that handles all my socket.io events. - Modifiy
package.json
to runnode ./bin/wwwio
onnpm start
instead ofbin/www
You can also look at the answers on this other question about the some topic:
Using socket.io in Express 4 and express-generator's /bin/www
You'll find several approaches to achieving modularity with little touching on the bin/www
script.
Related Topics
Passing Variable from JavaScript to Ruby on Rails
How to Create Query Parameters in JavaScript
Why How to Not Define Functions in Jquery's Document.Ready()
The Invocation Context (This) of the Foreach Function Call
R Networkd3 Package: Node Coloring in Simplenetwork()
Ruby Hash Equivalent of JavaScript's Object Initializer Es6 Shorthand
Twitter Bootstrap Rails Button Dropdown No Responding to Ajax
Space Filling with Circles of Unequal Size
Accessing ASP.NET Controls Using Jquery (All Options)
Rails - How to Include JavaScript Files Only on Certain Pages
How to Read Console Logs of Wkwebview Programmatically
How to Use JavaScript Variables in Ruby
How to Get an Ajax Get-Request to Wait for the Page to Be Rendered Before Returning a Response
How to Pass Data from JavaScript to Swift Within a Wkwebview
How to Bring a Circle to the Front with D3
Rails 4 - Gmaps4Rails - Map Won't Render
Why am I Getting Weird Result Using Parseint in Node.Js? (Different Result from Chrome Js Console)