Node.js – Load modules from specified directory recursive

Recently I have introducted Node.js and Express framework into my project which is very modular.

One of principles is that each functionality is encapsulated into a Controller known from web applications

frameworks like as Spring, Zend, Symfony, etc. Controller is nothing other than a function/method that will be executed, when the client’s HTTP request incomes.

It is very convenient to autoload all controllers from specified directory, which intends to register into URL routing registry. Assume, that all controllers exists in /src/Controller/ directory.

We could use the fs module from the Node.js standard library and call fs.readdir(path) or fs.readdirSync(path), but methods doesn’t works recursive. There is a lot of methods to walk trought the directory tree, but I have used an existing wrench module written by Ryan McGrath.

The usage

of my ModuleLoader

moduleLoader.loadModulesFromDirectory(path, onLoadCallback)

where onLoadCallback is function(module, moduleName, filePath).

Code

exports.loadModulesFromDirectory = function(dir, onLoadCallback) {
  require('wrench').readdirRecursive(dir, function(error, files) {
    if(null === 
files) return; for(var i = 0, j = files.length; i < j; ++i) { var file = files[i]; if(!file.match(/\.js$/)) continue; var moduleName = file.substr(0, file.length - 3); var filePath = dir + "/" + file; var module = require(filePath); onLoadCallback(module, moduleName, filePath); } }); }

Simple. Let’s use

this to load our Node.js and Express web application controllers:

1. Create the package.json file:
{
  "name": "hello-world",
  "description": "testapp",
  "dependencies": {
    "express": "3.2.6",
    "wrench": "1.5.1"
  }
}
2. Create the server.js file which will contain our web server:
var express = require('express');
var app = express();
var routes = require('./config/routes');

var port = process.env.port || 3000;

console.log('Starting server at port ' + port);

routes.setup(app);
app.listen(port);
3. Define our ./config/routes.js file:
function setup(app) {
  var moduleLoader = require('ModuleLoader');
  var path 
= __dirname + "/../src/Controller"; moduleLoader.loadModulesFromDirectory(path, function(module, moduleName, filePath) { var loadingState =
""; if(typeof module.registerAutoload === 'function') { module.registerAutoload(app); loadingState = "OK"; } else { loadingState = "FAILED"; } console.log("Loading Controller >> " + moduleName + " >> from file " + filePath + ": " + loadingState + "."); }); } exports.setup = setup;
4. And the last one… create our test controller in ./src/Controller/Test.js:
actionHello = function(req, res) {
  res.end('Hello! Server date: ' + new Date());
}

exports.registerAutoload = function(app) {
  app.get('/hello', actionHello);
}

If controller’s intention is not to autoload, just don’t implement exports.registerAutoload method. It works like the autoloading controllers from specified namespace in Spring Framework to look up for classes with @Controller annotation.

5. Now run our app!

To install all dependencies, use npm (Node Packaged Modules):

npm install

After installing all dependencies, the node_modules wil be created. Now, ust run our app:

node server.js

Now, lunch: http://localhost:3000/hello

Pretty, isn’t it?

Hope it helped.