Sharing variables across files in node.js without using global variables - node.js

I'm trying to separate my socket.io code into a separate file (socket.js) from my main file (app.js). However, I need to define my io object in app.js, which is also used in my socket.js file.
Currently, I set io as a global variable so it is accessible from app.js (Global Variable in app.js accessible in routes?), but I understand this is bad practise. Is there a better way to do this (can injection work in this case, as I need to export a variable from the app.js to socket.js rather than the other way round)? Thank you!
app.js
var app = express(),
server = require('http').createServer(app);
//KIV -> io is set as a global variable
io = require('socket.io').listen(server);
require('./socket');
socket.js
io.sockets.on('connection', function(socket) {
//xxx
}

One of the ways is by passing the object as argument to function (as already has been described in #Thomas' answer).
Other way is to create a new file say 'global.js'. put only those items in this file that you want to be global. e.g.
var Global = {
io : { }
};
module.exports = Global;
Now, in your app.js,
var app = express(),
server = require('http').createServer(app),
global = require('./global.js');
global.io = require('socket.io').listen(server);
require('./socket');
And in your socket.js:
var global = require('./global.js');
global.io.sockets.on('connection', function(socket) {
//xxx
}
Hope it helps...

app.js
var app = express(),
server = require('http').createServer(app),
socket = require('./socket');
var io = require('socket.io').listen(server);
socket(io)
socket.js
module.exports = function (io) {
io.sockets.on('connection', function(socket) {
// Your code here
});
}

Related

How to deal with socket.io being undefined in app.js

My express app logic is separated into a separate file from the instantiation of the express server, so I'm having issues with accessing socket.io within this app file. Should I just move the socket.io implementation into index.js or is it possible to keep that logic in app.js?
index.js
const http = require('http');
const app = require('./app');
const server = http.createServer(app);
const io = require('socket.io')(server);
const config = require('./utils/config');
const logger = require('./utils/logger');
app.set('socketio', io);
server.listen(config.PORT, () => {
logger.info(`Listening on port ${config.PORT}`);
});
app.js
const express = require('express');
const config = require('./utils/config');
const middleware = require('./utils/middleware');
const app = express();
app.use(middleware.requestLogger);
const io = app.get('socketio');
io.on('connection', (socket) => {
io.emit('test', { test: 'test' });
});
app.use(middleware.errorHandler);
module.exports = app;
You have a load order problem. You are loading app.js into index.js BEFORE you create and set io as an app property. So, when app.js tries to use the io property, it hasn't yet been set.
The way you have things split between the files, you've created a circular dependency. You can't create io until you've created the server, but you can't create the server until you have the app which is in app.js. So, you can't create io before you load app.js.
There are lots of ways around this. I find it kind of weird that you're creating the server in one file and the app object in another file since the two are fully required to make an operational server. So, I'd rearrange how those things are done like this:
// index.js
const http = require('http');
const app = require('express')();
const server = http.createServer(app);
const io = require('socket.io')(server);
app.set('socketio', io);
require('./app.js')(app);
const config = require('./utils/config');
const logger = require('./utils/logger');
server.listen(config.PORT, () => {
logger.info(`Listening on port ${config.PORT}`);
});
And, then modify app.js like this:
const config = require('./utils/config');
const middleware = require('./utils/middleware');
module.exports = function(app) {
app.use(middleware.requestLogger);
const io = app.get('socketio');
io.on('connection', (socket) => {
io.emit('test', { test: 'test' });
});
app.use(middleware.errorHandler);
}
There are 100 other ways to organize the code to fix this. Exporting a function that you can call and passing that function one or more arguments is one way to help control the timing of these circular dependencies.

Socket.io Middle-ware

I am wondering how can i make socket.io avail outside my app.js page. I have currently all my socket related code on the app.js page after
const express = require('express');
const app = express();
const socketio = require('socket.io
const expressServer = app.listen(9999);
const io = socketio(expressServer);
where i can use the io.xxx but what i rather would do is to initialize the socket.io and then put all related code into a separate file where i can then expose functions to call emits etc.
You can put the socket.io code in it's own module and use exports to initialize and share the instance.
sio.js
const socketio = require('socket.io');
let io;
module.exports = {
init: function(server) {
if (io) {
throw new Error("socket.io already initialized");
}
// initalize socket.io to this server
io = socketio(server);
// put other socket.io initialization code here
return io;
}
get: function() {
if (!io) {
throw new Error("socket.io has not yet been initialized");
}
return io;
}
}
app.js
const express = require('express');
const app = express();
const expressServer = app.listen(9999);
const io = require('sio').init(expressServer);
some other module file that wants access to socket.io instance
const io = require('sio').get();
This allows one socket.io instance bound to one server per process (because the io instance is stored in module data). It could be extended to support multiple instances for multiple servers, but you'd then have to say which server you wanted the instance for when requesting the instance.
Note also that the .init() method must be called before the .get() can be called so the sio module should be loaded and call .init() on it early in the app module's setup before it loads other things that themselves might want to load sio.

Separating modules in NodeJS for use with a single object

I have a NodeJS + ExpressJS + Socket.IO server and I am trying to divide my different namespaces into different modules.
Essentially I want to require the socket.io library in server.js, but have access to the io variable from my modules like this:
server.js
var app = require('express')();
var jwt = require('jsonwebtoken');
var server = require('http').Server(app);
var fs = require('fs');
var io = require('socket.io')(server);
var bodyParser = require('body-parser');
var _log = require('./logging/loggly.js').Client();
// Global NS
var SK = {
Namespaces:{}
};
var Migrations = require('./sockets/migrations');
var Backups = require('./sockets/backups');
var Cloudmanager = require('./sockets/cloudmanager');
SK.Namespaces[Migrations.NS] = Migrations;
SK.Namespaces[Backups.NS] = Backups;
SK.Namespaces[Cloudmanager.NS] = Cloudmanager;
....
....
migrations.js
var exports = module.exports = {};
///////////////////////////////////////////////
//
// Migrations Namespace
//
///////////////////////////////////////////////
exports.NS = 'migrations';
exports.socket = io.of('/'+exports.NS); // PROBLEM IS 'io' IS UNDEFINED HERE
exports.socket.on('connection', function(socket){
});
I have basically the same code in all 3 of my socket.io namespaces, but I don't have access to the io variable that is used in server.js. Is there a way to have access here? Do I just use a require()? Whats the best way to achieve this functionality?
Thank you
You can export a function from migrations.js that accepts the io value as a parameter:
module.exports = function (io) {
var socket = io.of('/'+exports.NS);
socket.on('connection', function(socket){});
return {
NS: 'migrations',
socket: socket,
};
};
Then simply require and invoke this function in your server.js:
var Migrations = require('./sockets/migrations')(io);

How to access io instance in a third part file?

I need to access my socket.io instance in some differents files, how do you make it works?
Here is what i tried:
main.js
var app = express();
var sockets = require('./sockets');
sockets.listen(app)
sockets.js
var io = require('socket.io');
exports.listen = function(app) {
io = io.listen(app);
//...
}
exports.io = io;
SomeClass.js
var io = require('./sockets').io;
var SomeClass = function() {
var Clients = io.sockets.clients('room');
//io is undefined...
}
exports.SomeClass = SomeClass;
In your file, io.sockets is undefined because you are starting your server incorrectly. Socket.IO expects a HTTP server instance, and you are instead passing an Express instance. You are also trying to change a variable after it has been exported, and that does not work. This is what you should be doing:
var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server):
server.listen(80);
If you still wanted to split this up into files, you would have to put your Socket.IO instance in your main application, and pass it to other modules when requiring them.

Need for module.parent in the following node.js code

const PORT = 3000;
const HOST = 'localhost';
var express = require('express'),
http = require('http'),
server = http.createServer(app);
var app = express();
const redis = require('redis');
const client = redis.createClient();
const io = require('socket.io');
if (!module.parent) {
server.listen(PORT, HOST);
const socket = io.listen(server);
socket.on('connection', function(client) {
const subscribe = redis.createClient()
subscribe.subscribe('realtime');
...
...
});
});
}
I stumbled upon this piece of code in one of the sites , In the above code I want to know the reason why the condition (!module.parent) is used ??? Whats the need for using it ??
If there is no module.parent it probably means that the module is being run on its own rather than being used in another program. If the !module.parent block is in a utility module I would guess that it is code for a test or developer tool. In a program that does stuff on it's own (e.g. a webserver), it would probably be the main entry point and the purpose of using it would be to make it possible to require components of that program without running the program.

Resources