HTML5 Dev Gal

Messing with HTML5, CSS3 and JavaScript.

Create Dynamic Namespace Autoloader With Node.js, Express, and Walk

| Comments

I was tired of manually creating namespace objects for my javascript files so I decided to dynamically generate a namespace.js file based on the directory structure of my app.

Requirements

Node Modules

Instructions

Download and install a node.js binary.

Create a project folder and navigate to it:

mkdir app
cd app

Install the npm modules. The -S flag will save the dependency info to your package.json file:

npm install express walk -S

Set up express in your app. If you don’t know how to do this, check out the express guide or checkout the Using express(1) to generate an app section in the guide to auto generate a node.js / express app.

In your server.js or app.js file (which ever one you’ve created for express) do the following:

Make sure you are requiring the nescessary modules. You probably need more but these are just for the code in this example:

Modules Required
var express = require('express'),
    http = require('http'),
    fs = require('fs'),
    walk = require('walk');

To run the http server in express you probably have something like this in the file:

http.createServer function
http.createServer(app).listen(app.get('port'), function(){
    console.log("Express server listening on port " + app.get('port') + " in " + process.env.NODE_ENV + " mode.");
});

To auto generate the namespace file when the http server starts, modify the http.createServer code block to look like this. Make sure to replace following variables:

  • startPath - path where your app directory resides in relation to the server.js / app.js file.
  • appName - global namespace.
  • filePath - path of the file you want to write the namespace code to.
Code to Add
http.createServer(app).listen(app.get('port'), function(){
    console.log("Express server listening on port " + app.get('port') + " in " + process.env.NODE_ENV + " mode.");

    var emitter,
        str,
        startPath = "public/javascripts/poc",
        appName = "poc",
        filePath = "public/javascripts/poc/namespace.js";

    var log = fs.createWriteStream(filePath, {'flags': 'w'});
    var spacedStartPath = startPath.replace(/\//g, " ");

    function upperCaseMe (txt){
        return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
    }

    str = "window." + appName + " = {} || " + appName + ";\r\n";
    emitter = walk.walk(startPath);

    emitter.on('directory', function (path, stat, next) {
        var dirpath =  [path, '/', stat.name].join('');

        var noSlash =  dirpath.replace(/\//g, " ");
        var strip =  noSlash.replace(spacedStartPath,"");
        var uppercase = strip.replace(/\w\S*/g, upperCaseMe);
        if (uppercase.indexOf(" ") != -1) {
            uppercase = uppercase.replace(/ /g,".");
        };
        var end = " = {};\r\n"
        str += appName + uppercase + end;

        next();
    });

    emitter.on('end', function () {
        log.write(str);
    });

});

With this example and this app directory structure

poc
--data
----api
----layout
----providers
--grid
--models
----view

the autogenerated namespace file looks like this:

namespace.js
window.poc = {} || poc;
poc.Data = {};
poc.Grid = {};
poc.Models = {};
poc.Models.View = {};
poc.Data.Api = {};
poc.Data.Layout = {};
poc.Data.Providers = {};

This way I can take the following file:

poc/data/providers/names.js

and use the following namespace / naming convention code to define a global method / object:

Example Method
poc.Data.Providers.Names.globalvar = "globalvarval";
poc.Data.Providers.Names.globalmethod = function(){
// awesome code here
};

I got a twitter response from a one of the great JavaScript masters Dr. Axel Rauschmayer when asking if his lobrow library could be used to do this only using browser modules. I wasn’t able to do it and wound up with this solution but he gives some tips:

I hope someone finds this helpful!

Comments