Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to structure a express.js application?

Is there a common convention for breaking up and modularizing the app.js file in an Express.js application? Or is it common to keep everything in a single file?

like image 383
Eric the Red Avatar asked Oct 11 '11 20:10

Eric the Red


People also ask

Is Express JS good for big projects?

Middleware frameworks, like Express. js, are suitable for small and medium projects. If you are going to develop a large project that will be supported by a large team of developers, Express. js is not the best choice.

Is Express JS good for production?

It's fast, unopinionated, and has a large community behind it. It is easy to learn and also has a lot of modules and middleware available for use. Express is used by big names like Accenture, IBM, and Uber, which means it's also great in a production environment.


2 Answers

I have mine broken up as follows:

~/app |~controllers | |-monkey.js | |-zoo.js |~models | |-monkey.js | |-zoo.js |~views | |~zoos |   |-new.jade |   |-_form.jade |~test |  |~controllers |    |-zoo.js |  |~models |    |-zoo.js |-index.js 

I use Exports to return what's relevant. For instance, in the models I do:

module.exports = mongoose.model('PhoneNumber', PhoneNumberSchema); 

and then if I need to create a phone number, it's as simple as:

var PhoneNumber = require('../models/phoneNumber'); var phoneNumber = new PhoneNumber(); 

if I need to use the schema, then PhoneNumber.schema

(which assumes that we are working from the routes folder and need to go 1 level up and then down to models)


EDIT 4

The express wiki has a list of frameworks built on top of it.

Of those, I think Twitter's matador is structured pretty well. We actually used a very similar approach to how they load up parts of the app.

derby.js also looks extremely interesting. It's akin to meteor without all of the hype and actually gives credit where credit is due (notably, node and express).


EDIT 3

If you are a fan of CoffeeScript (I am not) and reeeeaaaaaally want the L&F of Rails, there is also Tower.js.


EDIT 2

If you are familiar with Rails and don't mind the bleed-over of some concepts there is Locomotive. It is a light-weight framework built on Express. It has a very similar structure as RoR and carries over some of the more rudimentary concepts (such as routing).

It's worth checking out even if you don't plan to use it.


EDIT 1

nodejs-express-mongoose-demo is very similar to how I have mine structured. Check it out.

like image 185
Chance Avatar answered Oct 28 '22 17:10

Chance


Warning: referencing code I hacked together for node knockout, it kind of works but is far from elegant or polished.

To be more specific about splitting up app.js I have the following app.js file

var express = require('express'),     bootstrap = require('./init/bootstrap.js'),     app = module.exports = express.createServer();  bootstrap(app); 

This basically means I place all my bootstrapping in a seperate file, then I bootstrap the server.

So what does bootstrap do?

var configure = require("./app-configure.js"),     less = require("./watch-less.js"),     everyauth = require("./config-everyauth.js"),     routes = require("./start-routes.js"),     tools = require("buffertools"),     nko = require("nko"),     sessionStore = new (require("express").session.MemoryStore)()  module.exports = function(app) {     everyauth(app);     configure(app, sessionStore);     less();     routes(app, sessionStore);     nko('/9Ehs3Dwu0bSByCS');       app.listen(process.env.PORT);     console.log("server listening on port xxxx"); }; 

Well it splits all the server initialization setup in nice chunks. Specifically

  • I have a chunk that sets up all my remote OAuth authentication using everyauth.
  • I have a chunk that configures my application (basically calling app.configure)
  • I have a little bit of code that punches less so it re-compiles any of my less into css at run time.
  • I have code that sets up all my routes
  • I call this small nko module
  • Finally I start the server by listening to a port.

Just for example let's look at the routing file

var fs = require("fs"),     parseCookie = require('connect').utils.parseCookie;  module.exports = function(app, sessionStore) {     var modelUrl = __dirname + "/../model/",         models = fs.readdirSync(modelUrl),         routeUrl = __dirname + "/../route/"         routes = fs.readdirSync(routeUrl); 

Here I load all my models and routes as arrays of files.

Disclaimer: readdirSync is only ok when called before you start the http server (before .listen). Calling synchronious blocking calls at server start time just makes the code more readable (it's basically a hack)

    var io = require("socket.io").listen(app);      io.set("authorization", function(data, accept) {         if (data.headers.cookie) {             data.cookie = parseCookie(data.headers.cookie);              data.sessionId = data.cookie['express.sid'];              sessionStore.get(data.sessionId, function(err, session) {                  if (err) {                     return accept(err.message, false);                 } else if (!(session && session.auth)) {                     return accept("not authorized", false)                 }                 data.session = session;                 accept(null, true);             });         } else {             return accept('No cookie', false);         }     }); 

Here I punch socket.io to actually use authorization rather then letting any tom and jack to talk to my socket.io server

    routes.forEach(function(file) {         var route = require(routeUrl + file),             model = require(modelUrl + file);          route(app, model, io);     }); }; 

Here I start my routes by passing the relevant model into each route object returned from the route file.

Basically the jist is you organize everything into nice little modules and then have some bootstrapping mechanism.

My other project (my blog) has an init file with a similar structure.

Disclaimer: the blog is broken and doesn't build, I'm working on it.

like image 24
Raynos Avatar answered Oct 28 '22 15:10

Raynos