I'm developing my first Node.js App with Socket.IO and everything is fine but now the app is slowly getting bigger and I'd like to divide the app-code into different files for better maintenance.
For example I'm defining all my mongoose schemas and the routings in the main file. Underneath are all the functions for the socket.IO connection. But now I want to have an extra file for the schemas, an extra file for routing and one for the functions.
Of course, I'm aware of the possibility to write my own module or load a file with require. That just does not make sense for me, because I can't work with the vars like app, io or db without making them global. And if I pass them to a function in my module, I can't change them. What am I missing? I'd like to see an example how this is done in practice without using global vars..
It sounds like you have a highly coupled application; it's difficult for you to split out your code into modules because pieces of the application that should not depend on each other do. Looking into the principles of OO design may help out here.
For example, if you were to split your dataabse logic out of the main application, you should be able to do so, as the database logic should not depend on app or io--it should be able to work on its own, and you require it into other pieces of your application to use it.
Here's a fairly basic example--it's more pseudocode than actual code, as the point is to demonstrate modularity by example, not to write a working application. It's also only one of many, many ways you may decide to structure your application.
// =============================
// db.js
var mongoose = require('mongoose');
mongoose.connect(/* ... */);
module.exports = {
User: require('./models/user');
OtherModel: require('./models/other_model');
};
// =============================
// models/user.js (similar for models/other_model.js)
var mongoose = require('mongoose');
var User = new mongoose.Schema({ /* ... */ });
module.exports = mongoose.model('User', User);
// =============================
// routes.js
var db = require('./db');
var User = db.User;
var OtherModel = db.OtherModel;
// This module exports a function, which we call call with
// our Express application and Socket.IO server as arguments
// so that we can access them if we need them.
module.exports = function(app, io) {
app.get('/', function(req, res) {
// home page logic ...
});
app.post('/users/:id', function(req, res) {
User.create(/* ... */);
});
};
// =============================
// realtime.js
var db = require('./db');
var OtherModel = db.OtherModel;
module.exports = function(io) {
io.sockets.on('connection', function(socket) {
socket.on('someEvent', function() {
OtherModel.find(/* ... */);
});
});
};
// =============================
// application.js
var express = require('express');
var sio = require('socket.io');
var routes = require('./routes');
var realtime = require('./realtime');
var app = express();
var server = http.createServer(app);
var io = sio.listen(server);
// all your app.use() and app.configure() here...
// Load in the routes by calling the function we
// exported in routes.js
routes(app, io);
// Similarly with our realtime module.
realtime(io);
server.listen(8080);
This was all written off the top of my head with minimal checking of the documentation for various APIs, but I hope it plants the seeds of how you might go about extracting modules from your application.
Related
Let Me explain what I am working on .
I have included the express module in app.js .
Here I want to access this module in index.js , admin.js , gallery.js.
but I dont want to write the same code again in all over js file .
let me show you my scenario.
app.js has
var express = require('express');
index.js has
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;
gallery.js has
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.render('gallery', { title: 'Gallery' });
});
module.exports = router;
Here var express = require('express'); is already present in app.js .
I want to reuse it from app.js instead of including in every file .
What I have tried so far
I made global in app.js , so that I can access it all over
global.express = require('express');
this code is working for me .
Is this the correct approach or any other way to do or including express module in all the js file is fine ?
You can export your files (not app.js assuming this is your entry point) as a function and pass your express module into those files
gallery.js
module.exports = function(app) {
/* GET users listing. */
app.get('/', function(req, res, next) {
res.render('gallery', { title: 'Gallery' });
});
}
app.js
var express = require('express')
var app = express();
var galleryRoute = require('./gallery');
// Routes
galleryRoute(app);
I have read some where to avoid using Global Variables because there are some cons of it here are few of them:
The first reason is that when you create a global variable, it exists
throughout the lifetime of the application. When a variable persists
through the lifetime of the app it means that it is there, in memory,
occupying resources while the app is running.
Second, traditionally using global variables can cause concurrency
issues. If multiple threads can access the same variable and there
are no access modifiers or failsafes in place, it can lead to some
serious issues of two threads attempting to access and use the same
variable. However, while this is the case in other languages, it is
not necessarily the case for Node.js as it is strictly a
single-threaded environment. While it is possible to cluster Node
processes, there is no native way to communicate between them.
The last reason I am going to talk about is that using globals can
cause implicit coupling between files or variables. Coupling is not a
good thing when it comes to writing great code. When writing code, we
want to make sure that it is as modular and reusable as possible,
while also making sure it is easy to use and understand. Coupling
pieces of your code together can lead to some major headaches down
the road when you are trying to debug why something isn't working.
As for your question you can export the express from app.js or index and use it everywhere.
It is discouraged to use additional global variables as application already has 'export' and 'require' global variables. (exports/require are not keywords, but global variables.)
If you need to export the 'app' for other files, you can do something like below.
in index.js:
var express_app = module.exports = express();
now index.js can be required to bring app into any file.
in any.js file:
var express_app = require('./index');
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.
This has been driving me crazy. I'm new to NodeJS. I love it so far but some things have been throwing me off. I was handed a very basic starting point to a node project and I'm unsure how to search google for this.
//myapp/server.js
var config = require('./config');
var app = express();
var api = require('./app/routes/api')(app, express); // <-- this?
app.use('/', api);
var server = app.listen(3000, function () {
console.log('\n============================');
console.log(' Server Running on Port 3000 ');
console.log('============================\n');
});
Then there's the api.js file that contains the routes.
//myapp/app/routes/api.js
var config = require('../../config');
var mysql = require('mysql');
module.exports = function(app, express) {
var api = express.Router();
api.all('/', function(req, res) {...});
api.all('/route-two', function(req, res) {...});
api.all('/another-route', function(req, res) {...});
return api;
}
Ideally I'd like to break up what's going on here into a more organized structure but, I want to understand what I'm doing exactly.
The main thing that is confusing me is this line
var api = require('./app/routes/api')(app, express);
I was unaware that you can have ()() next to each other without a . or something joining them. Can someone explain what is happening?
Also what is the point of (app, express)? It appears that app and express are getting passed to the api part of the application so it's scope can be reached? Am I way off?
If there is a cleaner approach to this I would love to get some insight. I appreciate any thoughts.
Thanks!
EDIT
To make sure I am understanding...
var api = require('require this file')(params available to this file);
Moving any requires from api.js to server.js then include those as parameters
var api = require('./app/routes/api')(config, app, express, mysql);
EDIT
After more helpful feedback from #AhmadAssaf #Gurbakhshish Singh and #guy mograbi
Modules I want to use in another file other than where they are require()ed should be passed in through the second set of ()
//.server.js
var config = require('./config');
var app = express();
var api = require('./app/routes/api')(config, app, express);
| | |
_____________/______/________/
/ / /
//.app/routes/api.js | | |
module.exports = function(config, app, express) {
var api = express.Router();
// code to handle routes
}
Could be wrong with this part but based on what I think I am understanding.
//.server.js
var config = require('./config');
var app = express();
var register = require('./app/routes/register')(config, app, express);
var login = require('./app/routes/login')(config, app, express);
| | |
_________________/______/________/
/ / /
//.app/routes/login.js | | |
module.exports = function(config, app, express) {...handle login...}
//.app/routes/register.js
module.exports = function(config, app, express) {...handle registration...}
etc. etc.
Hopefully my thinking is about right. I appreciate everyones help on this! :)
So basically you have to understand few thing
module.exports wraps a Javascript object and export it to be used as a pluggable piece of code around a node.js application
The wrapped javascript object can be a JSON object, Javascript variable, function, etc.
What you have up there in the api module is a function that takes two parameters. When you require that module you want to pass some constructors to that function and thats the use of the second () after the module name in the first ()
requiring express once in your program and passing the variable around is more or less a singleton pattern. What you can also do is pass the config object as well to the api module instead of requiring it again :)
var api = require('./app/routes/api')(app, express);
is Equivalent to:
var myFunc = require('./app/routes/api');
var api = myFunc(app, express);
and becauase of NodeJS's module loading procedure, the require('...') will be
plugged in by the piece of code that was exported at the path, it can be a object, function, simple variable, etc.
And as far as ()() goes the require() nodeJS will make it something like function(){}() in your case and this is valid javascript and rather very useful to write IIFE(Immediately-Invoked Function Expression) code
Quesiton 1
explain ()()
every language where a function can return a function you can have this syntax. imagine the following
function world(){ ... }
function hello(){
return world;
}
// ===>
hello()() // ==> would invoke hello and then world.
So when you see require('..')() then it means require('..') returns a function. You do this by writing the following:
module.exports = function(){}
and that function returns yet another function - in your case this means express.Router(); returns a function.
Question 2
is there a cleaner way to write this?
this is a discussion.. which is hard to answer. depends on your preferences. The only thing I can think of that might help you reach an answer is to use the express generator and see the structure the express team uses.. which is probably as clean as it gets.
express can generate a project for you with some code to start with. simply install it with npm install -g express and then run express - it will generate the project for you in the same directory where you ran it.
go over the generated project. I suggest follow the same pattern - this is what i do whenever i cick-off a project.
If something is still unclear or if you need me to elaborate, please comment so and I will edit the answer.
module.exports from api.js is a function, which takes two arguments: app, and express. Therefore, when you require it in server.js with require('./app/routes/api'), the value returned is that function. Since it's a function, you can just call it by putting parentheses after it, and passing in the arguments it expects (app and express), like so : require('./app/routes/api')(app, express).
In Express 4, by default, routes are loaded from a separate file:
app.use('/', routes);
Would load routes/index.js.
I have a third-party library that attaches to app itself. Is there a preferred way to access app from inside routes/index.js?
I've thought about dependency injection ie, routes/index.js does
module.exports = function(app){
(routes go here)
}
and then:
app.use('/', routes(app))
But I wonder if there's a better way. What's the best way to access the express 'app' object from inside a separate route file?
You can simply access app by req.app in your route handlers
I looked at a number of app generators and everyone does it differently.
Mostly though I've seen it work the opposite from what you are asking. The route modules do not get the app passed in, they just return themselves and are attached to the app.
I like to use the following pattern:
routers/hello.js:
var express = require('express');
var router = express.Router();
router.get('/hello', function (req, res) {
res.send('Hello, World!');
});
module.exports = router;
app.js:
var express = require('express');
var app = express();
app.use('/sample', require('./routers/hello'));
// other routers are attached
module.exports = app;
server.js:
var http = require('http');
var app = require('app');
var server = http.createServer(app);
server.listen(3000):
So the modules in routers/ return an Express Router object that are then attached to the app on their respective paths (routes).
This is inspired on the Express Application generator, but uses Routes instead of Routers. My advice, use the linked generator and start from there.
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.