The following is my server.js file in my node.js application. I want my socket.io instance to be accessed by other files on my server in order to emit events from my API (listingRoutesApi, userRoutesApi etc.) (refer to code)
.
The problem I have is that my routes are declared before the server is created; however, the socket.io instance is created after the server is created.
The solution I've used is to declare a global io
variable that will allow me to emit events from anywhere within my web app like so:
global.io.of('/analytics').to(listing._id).emit('message', "There was a post.");
My question is: are there any pitfalls / dangers from doing this and will I encounter any scalability issues in the long-term? Additionally, is there a better way of achieving my objective?
Code within my server.js file:
const app = express();
app.use('/api', listingRoutesApi);
app.use('/api', userRoutesApi);
app.use('/api', imageRoutesApi);
// ...plenty more endpoints here...
app.use(serveStatic(path.join(__dirname, "/dist")));
app.use(history());
app.use(serveStatic(path.join(__dirname, "/dist")));
const server = app.listen(port, () => { console.log('server started ' + port); });
/* Start socket. */
global.io = socketio(server);
const analytics = global.io.of("/analytics");
analytics.on('connection', (socket) => {
socket.on('join', (data) => {
socket.join(data.room);
analytics.in(data.room).emit('message', `New user joined ${data.room}`);
});
socket.on('leave', (data) => {
analytics.in(data.room).emit('message', `User leaving ${data.room}`);
socket.leave(data.room);
});
socket.on('disconnect', () => {
console.log('user disconnected');
});
});
I'm asking this question since this SO post answers a similar question by declaring a getIOInstance
function and passes it to all modules that require it. While, it works, it doesn't feel very elegant and seems a little unnecessary given I expect to only ever have exactly one socket.io instance in my application.
Additionally, I would assume the challenge I'm having is a very common one; however, I haven't been able to find many solutions to address it and none that suggest using a global variable.
Node.js is a modular environment. Modules are suppose to address some flaws that globals have.
Modules naturally provide singleton instances, in case there's a need to have only one instance:
app.js
module.export = express();
server.js
const app = require('./app');
// can go to app.js if configured but unlistened app is needed for reusability or testing
app.use(/* router */);
module.export = app.listen(...);
socketio.js
const server = require('./server');
module.export = socketio(server);
index.js
const app = require('./app');
const io = require('./socketio');
...
Express also provides a container for application global dependencies, application settings table. It can be used everywhere application instance is available, e.g. as req.app.get(...)
inside middlewares. Accessing Express application instance outside middlewares won't be a problem if it's a singleton as well:
app.js
module.export = express();
index.js
const app = require('./app');
app.use(/* router */);
...
const server = app.listen(...);
const io = socketio(server);
app.set('io', io);
// available as req.app.get('io') inside middlewares
// and as require('./app').get('io') outside them
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With