Exporting HTTP server for socket.io not working - javascript

I have a app.js
const express = require('express');
const app = express();
const server = require('./server.js');
// app.use
const io = require('socket.io').listen(server);
io.on('connection', function (socket) {
...
});
module.exports = app;
And a server.js
const app = require('./app');
const server = app.listen(5000 || process.env.PORT, () => {
console.log('App listening on port 5000!');
})
module.exports = server;
If I put the server in a separated file the socket is not working, but if I start the server inside the app.js the socket works.
What I'm doing wrong?

The issue here is that you have a circular dependency where app.js is loading server.js and server.js is loading app.js. You can't do that for this type of code.
It has an issue because you're trying to load server.js from within app.js and then in the process of loading server.js, it attempts to load app.js and get its exports, but app.js hasn't finished loading yet and thus hasn't even returned its exports yet. So, the loader either thinks there are no exports or recognizes the circular request (I'm not sure which), but in either case the exports from app.js don't work because of the circular requires.
There are several different ways to solve this. The two most common ways are:
Break some code into a common third module that each of these can load and only have one of these load the other.
Rather than having server.js load app to get the app object, have app.js pass the app object to server.js in a constructor function rather than trying to execute at module load time.
Here's how the constructor function idea would work:
app.js
const express = require('express');
const app = express();
// load server.js and call it's constructor, passing the app object
// that module constructor function will return the server object
const server = require('./server.js')(app);
// app.use
const io = require('socket.io').listen(server);
io.on('connection', function (socket) {
...
});
module.exports = app;
server.js
// export constructor function that must be called to initialize this module
module.exports = function(app) {
const server = app.listen(5000 || process.env.PORT, () => {
console.log('App listening on port 5000!');
});
return server;
};
So, rather than server.js trying to load the app.js module to get the app object, the app object is "pushed" to it with a constructor function. This prevents the circular dependency.

Related

Express.js - prepend sub-route to all defined routes

Let's say I have an Express app defined in a file, say server.js like this:
const app = express();
app.use('/foo', foo);
app.use('/bar', bar);
module.exports = app;
I import this Express app in another file, say index.js:
const app = require('./server');
const port = process.env.PORT || 3000;
const listen = (port) => {
app.listen(port, () => {
console.log(`Backend listening on port ${port}!`);
});
};
listen(port);
Now, the routes that are available for this app are /foo and /bar.
Is there a way to edit configuration in the index.js file so that the routes become /api/foo and /api/bar? Without touching server.js file.
Use case:
I have a Nuxt.js app with a backend that is loaded into the Nuxt app via serverMiddleware property in nuxt.config.js like this:
serverMiddleware: [
...
{ path: '/api', handler: '~/server.js' },
],
This has the effect similar to what I described above: it imports the express app from server.js app and prepends all its routes with /api.
However, often I don't want to develop the frontend part of the Nuxt app, I just want to do changes on the backend. For this purpose I have a helper file like index.js above, which runs backend only. (Frontend often takes long time to compile, that's why I don't want to compile it when I don't need to.)
This creates a problem that all the routes are slightly different - they lack the /api at the beginning. The routes are being used in different tools like Postman etc. and suddenly they wouldn't work.
My current solution is to define index.js file in the same way as server.js file with all routes defined like I want them - instead of app.use('/foo', foo); there's app.use('/api/foo', foo); etc. but this has its own problems, e.g. if I change server.js I have to change index.js. I am looking for something more elegant.
According to the express 4.0 docs https://expressjs.com/en/4x/api.html#app.use you can use an application instance the same as you would a router. In short, just use the export of your server.js as a middleware at the route in which you want to insert it, as opposed to directly calling .listen() on it.
Here is some demo code that worked for me:
const express = require('express');
const app_inner = express();
app_inner.use('/foo', (req,res) => res.send('foo'));
const app_outer = express();
app_outer.use('/foo2', app_inner);
app_outer.listen(9999);
// web browser at localhost:9999/foo2/foo returns 'foo' as expected

Using modules.exports in main Node file

I initialized my socket.io server in my server.js file (main entry point).
EDIT 2: Importing otherfile.js in this file also
// server.js
const io = require('socket.io')(server);
const otherfile = require('otherfile.js');
io.use(//...configuration);
io.on("connection",otherfile);
module.exports = {io: io}
Now I want to use this same io object in another file
EDIT 1: To clarify, I am calling the exported variable in an export block like so:
// otherfile.js
const io = require('./server.js')['io'];
module.exports = {
function(socket){
// do stuff...
io.emit("event", payload);
}
}
When I run it, I get an error
Type Error: Cannot read '.on' property of undefined
Something like that.
Why can't I access code from the main js file?
I figured it out after reading this great article (well, parts of it :p) about requiring modules in Node. Under "Circular Module Dependency".
The problem was, I was exporting the io object after I had required the 'otherfile.js' so the io object had not yet been exported and therefore undefined in 'otherfile.js' when the code is called.
So just export io object before requiring 'otherfile.js'.
// server.js
module.exports = {
io: io
}
const otherfile = require("otherfile.js");
// listen for events...

Can someone explain how i can use module.exports this way

I am trying to understand what is going on when I use module.exports with a variable in a model view controller type project. I just do not understand what the book means by using it in this way
var express = require("./config/express.js");
var app = express();
app.listen(3000);
module.exports = app; // my problem is right here what is it doing
console.log("Server running at http://localhost:3000/");
my config/ express file is also here
var express = require("express");
module.exports = function()
{
var app = express();
require("../app/routes/index.server.routes.js")(app);
return app;
}
The first example is exporting the Express app directly and the second example is exporting a function that returns the Express app.
This means that in the first example, require(...) will return app. In the second example, you would need to do require(...)() to have app returned.

How to access a required module from different files?

In Node.js I'm using Socker.io in my main.js like this
const io = require('socket.io')(http);
Also Im using a "sub"-file like api.js which I want to use to delecate some of my business logic away from the main. So I imported also this one like
const api = require('./api.js');
In my api.js how can I now use the socket.io framework? Can I access the instance from above from a different file? Or do I have to pass the "io"-object like this: api.myFoo(io);
Every place that you say require('module') you will get the same instance of that module.
But here when you want to share the return value of a function, then you have to export it explicitly:
const io = require('socket.io')(http);
module.exports = io;
in some module, and require it in another modules by:
const io = require('./your-module');
Other option would be to pass it as an argument to other modules, like this:
const io = require('socket.io')(http);
const api = require('./api.js')(io);
but in that case your api.js would have to export a function that takes io as an argument:
module.exports = (io) => {
return ... // return whatever was exported before
};

Does module.exports have to be defined when require()-ing a file?

I'm using Babel to transpile my ES6 files on the fly on an Express server. In my server.js file (vanilla JS), I put require('babel-core/register') and require('./app').
In app.js (ES6), I do all my normal Express stuff stuff:
import express from 'express';
let app = express();
app.listen(3000, () => {
console.log('Server listening on port 3000');
});
... etc
Even though I don't formally define module.exports in my app.js file, when I run node server, app.js gets correctly required and runs. Why does this work?
When you require a module, the code inside that module will be executed, but it is executed only once. Subsequent require calls to the same module will have no effect except to return whatever the module exports. That's the nature of node modules (look for the note on 'caching'). By using module.exports you are basically designating a return value for it.
You don't need to export anything in your case, the app.listen line is called as soon as you require app.js. Although you could export an API or something like this if you wanted to:
/*app.js*/
import express from 'express';
let app = express();
module.exports = {
start:function(){
app.listen(3000, () => {
console.log('Server listening on port 3000');
})
}
/*server.js*/
require('babel-core/register');
var app = require('./app');
app.start();
I might be misunderstanding the question, but I don't think babel and express are relevant really.

Categories

Resources