In my app.js, i have constructed a redis client:
var redis = require('redis'),
redisClient = redis.createClient(6379, 'localhost');
...
module.exports = {
app:app,
redisClient:redisClient
}
I need to use the redis client in my other module, which is routes/index.js. here, i tried including it like so:
var redisClient = require('../app').redisClient;
Unfortunatly, it is undefined.
Should i just require it in the index.js like i did in the app.js, and create a new instance here? Or what could i change to make it work?
Related
I am a bit confused, about how to require and use modules in Node.js.
My scenario is the following:
I wrote a complete server in one single file, which uses Socket.io for realtime communication.
Now the index.js became pretty big, and I want to split the code into several modules to make it more managable.
For example I have some functions for serving a Survey to the clients, and getting back their answers. I put all those functions in a seperate module, and require it in the index.js. Works fine so far.
The only thing I am concerned about is, if there is another way to use the SAME socket instance inside the module.
My current coding looks like this:
index.js:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var Survey = require('./survey');
io.on('connection', function (client) {
client.on('getCurrentQuestion', function (data) {
Survey.getCurrentQuestion(parseInt(data.survey_id), client.id);
});
});
server.listen(port, server_url, function () {
Survey.init(io);
});
survey.js:
var io = null;
var Survey = {};
Survey.init = function(socketio) {
io = socketio;
};
Survey.getCurrentQuestion = function(survey_id, socket_id) {
var response = {
status: "unknown",
survey_id: survey_id
};
// [...] some code that processes everything
// then uses Socket.io to push something back to the client
io.sockets.in(socket_id).emit('getCurrentQuestion', response);
};
module.exports = Survey;
This way it works, but I'm not happy passing io inside an init function to the required module.
What would be "the right way" to do this?
If I require('socket.io') inside the survey module, will it be the same instance as in index.js?
How would I even require that, since it needs the server, which needs the app, which is created in index.js?
I am confused and hope that somebody can help me. Thanks!
When you import a node.JS library you can also pass in objects. In your case the index.js file should be changed to the following:
//index.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var Survey = require('./survey')(io);
Then just change your survey.js code to take the io object:
//survey.js
module.exports = function (io) {
var Survey = {};
Survey.getCurrentQuestion = function(survey_id, socket_id) {
var response = {
status: "unknown",
survey_id: survey_id
};
// [...] some code that processes everything
// then uses Socket.io to push something back to the client
io.sockets.in(socket_id).emit('getCurrentQuestion', response);
};
return Survey;
};
To answer your other question:
If you require('socket.io') inside the survey module, it will be a different instance from index.js.
EDIT
If you want a more modern way of doing it...You could use ES6 format and create a class to do this better:
'ES6 index.js
import SurveyClass from './Survey';
import * as express from 'express';
let app = express();
let server = require('http').createServer(app);
let io = require('socket.io')(server);
let MySurveyClass= SurveyClass(io);
let myInstance = new MySurveyClass();
myInstance.getCurrentQuestion(5, "some-socket-id");
'ES6 survey.js
export default class Survey{
constructor(io){
this.io= io;
};
getCurrentQuestion(survey_id, socket_id) {
var response = {
status: "unknown",
survey_id: survey_id
};
// [...] some code that processes everything
// then uses Socket.io to push something back to the client
this.io.sockets.in(socket_id).emit('getCurrentQuestion', response);
};
}
When you do this in multiple modules:
var socketio = require('socket.io');
then it will be the same object for all requires.
But if you do this:
var io = require('socket.io')(server);
even if you have the same object in server in both places, io would be a different value because it would come from different invocations of the function returned by require('socket.io') even though those functions would be the same.
If you want to make sure that the io is the same then you'd have do e.g. something like this: Make a module that exports a promise of io and some way to initialize it - a function that gets the server and everything needed. Now, in the place where you have the server you can require the module and initialize it with that exported function, and in other places you can import the module and use a promise.
Instead of a promise you could use callbacks or even just a property on the exported object that could be initially undefined and gets defined when the socket.io is initialized but using a promise would probably be most simple solution to make sure that you're not using it while it's not ready yet.
You didn't mention in your question whether or not you use some framework and which one if any, but some of the frameworks like Hapi give you an easy way to share functionality like that. E.g. see:
https://hapijs.com/tutorials/plugins
If you use Hapi then you should use plugins. If other framework then search for a similar feature.
Started a project with npm which created a certain file structure:
www <-- require() calls app.js; instantiates server
app.js <-- instantiates var app = express(); and has module.exports = app;
Now, I'd like to use sockets.io. In my 'www' file, here is a code snippet:
var app = require('../app');
...
var server = http.createServer(app);
And I'd like to put all of my server-side socket listeners in app.js, but the following code:
var io = require('socket.io').listen(server);
requires server as an input. How do I make the server I instantiated in 'www' accessible in 'app.js'?
It seems a little strange. But if you insist on such a structure than you can export an object from www that will have app as it's property and a method that binds socket listeners an receives app object as a param.
module.exports = {
app: app,
bindSocketListeners: function(server, io) {
io.listen(server);
return io;
}
};
And call it:
var appObj = require('../app');
var io = require('socket.io');
var app = appObj.app;
var server = http.createServer(app);
io = appObj.bindSocketListeners(server, io)
I'm trying to use Bookshelf along with Express 4.0 and can't seem to get them working together or rather, I can't seem to follow "best practices". The Bookshelf docs mention that one should always reuse the same instance of it throughout the app. It even lists an example:
// When the app starts
var app = express();
var knex = require('knex')(dbConfig);
var bookshelf = require('bookshelf')(knex);
app.set('bookshelf', bookshelf);
// elsewhere, to use the bookshelf client:
var bookshelf = app.get('bookshelf');
var Post = bookshelf.Model.extend({
// ...
});
However, I can't seem to get it working when I have to use app.get() in a separate file. For example, here's my app.js file (the root of my entire app):
var express = require('express');
var app = express();
var db = require('./server/db/db');
app.set('bookshelf', db);
var api = require('./server');
app.use(api);
Here's my db.js file that gets required above:
var express = require('express');
var app = express();
var knex = require('knex')({ //my db settings go here });
var bookshelf = require('bookshelf')(knex);
module.exports = bookshelf;
The above code works if I require it directly. Here's where the issue turns up. Whenever I want to actually use the bookshelf connection, no matter what file I'm in, I follow the same process but it fails and "bookshelf" is always undefined. Here's an example of an index.js file that's required and called "api" in the app.js:
var express = require('express');
var app = express();
var db = app.get('bookshelf');
console.log(db);
DB always comes up as undefined. Whenever I try to make a new Model, I use the same process except I do an db.Model.extend({}) and trying to access the Model property throws an error (because it's undefined).
From what I can use both Bookshelf and Express docs agree that this should work and it doesn't. Any ideas?
This line creates a new app every time you call it:
var myApp = express();
If you want to set or get variables from the same app, you'll have to pass it as an argument.
var api = require('./server')(myApp);
And then in your api module:
module.exports = function(app){
var db = app.get('bookshelf');
//....
};
On a side note: you don't have to worry about singletons in Node.js all you have to do is just require it.
var db = require('./path/to/db/config');
It'll only be instantiated once and cached for later calls.
How can I export these variables so I can later use them on different js files?
The following example works well with just 1 variable
var app = module.exports = express();
But I want to pass more variables so I did this
var app = express();
var connection = mysql.createConnection({
host : 'localhost',
user : 'root',
password : ''
});
module.exports.app = app;
module.exports.connection = connection;
with no success
This is because on the first, your module is the app. I mean that if you have B like that in the first case:
app = require('A') // = express()
whereas on the second time it is :
app = require('A') // = {app: express(), connection: connection}
The answer is in the Node.js Modules documentation:
You either assign the value that you want to export to the module.exports property, or you assign an object to it.
mymodule.js:
var app = module.exports = express();
Or:
var app = express();
module.exports = {
"app": app,
"otherproperties": "you want to export"
}
To require a module that you made yourself and didn't place node_modules directory, you can either supply an absolute path or a relative path.
Calling module:
var app = require("/home/user/myapp/mymodule.js"); // absolute path
app; // access returned value of express() function, created in *mymodule.js*
Or:
var app = require("./mymodule.js"); // path relative to the calling module
// In this case the calling module is in the same directory as *mymodule.js*
app.app; // access returned value of express() function, created in *mymodule.js*
Addendum: Even though the modules library/module has been locked, I really recommend reading the documentation. It's very much possible to read the entire documentation in two evenings while looking up network terminology that you're not familiar with. It'll save you a lot of time in the short term!
This is how my app.js looks
var app = require('http').createServer(handler),
io = require('socket.io').listen(app),
static = require('node-static'); // for serving files
var game = require('./game.js').createGame();
// This will make all the files in the current folder
// accessible from the web
var fileServer = new static.Server('./');
// This is the port for our web server.
// you will need to go to http://localhost:8080 to see it
app.listen(8080);
// Listen for incoming connections from clients
io.sockets.on('connection', function (socket) {
handle Events ...
});
exports.io = io;
exports.game = game;
when I try to access the created socket.io listner or the game instance I get error saying its undefined.
This how I am trying to access it in trick,js
var game = require('./app.js').game;
var socketio = require('./app.js').io;
var PlayerMove = require('./playerMove.js');
This might be because trick.js is actually executed before app.js (I put debug points and it was confirmed there). How do I avoid this? Is there a better way of exposing object instances in node.js, some pattern that i should probably use ?
declaring a variable does not export it. If you need to export something for your module, you should use exports.myVariable = myValue.
requiring your app.js file for the first time will run it. So everything you export in it will be available once you're out of the require() call