Creating Namespaces in Javascript

I may be the only one who absolutely hates relative paths within javascript with such a fervor. It makes code ugly and heavily linked to explicit a file structure rather than folder structure.

So I made this module Namespacer-js which should make requiring internal modules a much easier task, but first let’s explain why I made it.

It doesn’t help when your application configuration is the source of paths to the rest of your application and each internal component needs to pull it in to know about other parts.

Having to type this atrocity is bad.

#app/someService/service/someModule.js
const config = require('../../../config/app.js');

//or
const path = require('path'),
      config = require(path.resolve('./config/app.js'));

//Getting the model
let someModel = config.someService.models.someModel

The corresponding config file also relies on being the glue that pulls in the relative paths of all your internal modules.

#config/app.js

const path = require('path'),
      glob = require('glob');

const globs = {
    models: 'app/*/models/*.js'
};

//Add logic to transform globs to objects

I’ve seen this type of application configuration discovery and found it to be too tightly coupled to specific files and object structures. Changing the config location and you have to change every module that pulls in the configuration object. You can get around this by adding variables to the global space but then you’re polluting the global variable space.

Using a namespacer allows you define aliases, and specifically aliases that don’t have to be compiled to be used. It also allows the application to be very loosely coupled. Using a module which holds the global state simply including the module allows access to the global state without having to pollute the global object.

#config/app.js

const { namespace } = require('namespace');

namespace.addSpacesFromFile('./.spaces.js');
#.spaces.js

modules.export = {
    'SomeService' => 'app/someService/',
    'Config' => `app/config/${process.env.NODE_END}`,
    'Lib' => 'app/lib'
}
#app/someService/service/someModule.js
const { namespace: n } = require('namespacer-js');

const logger = n.require('Lib/logger.js'),
      models = n.require('SomeService/Model/*');

logger.info('Hello world');

//Load models
models.map((obj) => obj.load());

This type of configuration completely separates you from relative pathing and allows you to create more explicit structure via folders. Now it may seem backwards that you’re moving from relative files to explicit folders and files but it loosely couples your dependencies. Without any part of your application knowing you can have dynamically changing namespaces based on environment.

A future version I’m planning to allow the option to mangle the global require to override behavior to include namespaces so you don’t need to include require(’namespacer-js’). All you would need to do is make sure before you require into a namespace is that you define your spaces and call something like namespace.mangle() and then continue on your merry way.

If you structure your namespaces in a specific way and put your models in a single folder rather than attempting multi module models glob (which you can still do with the module) you can load and register them by simply requiring the namespace glob.

const { namespace: n } = require('namespacer-js');

//Include all models in immediate Models/ namespace directory
n.require('Models/*');

//Include all models in entire Models/ namespace
n.require('Models/**');

The difference between these two being that you can include an entire namespace subfolders included, or limit it to a single folder, and this should work for any subspace of the root namespace. So you could include ‘Models/mocks/’* if you’re in a testing environment. This works well with Mongo and Mongoose.

Devils Advocate

Now to give some alternative solutions a chance I found good article by branneman here describing better ways to do local require() paths.

Create a symlink under node_modules to your app directory:

Linux: ln -nsf node_modules app

Windows: mklink /D app node_modules

Now you can require local modules like this from anywhere:

var Article = require(‘models/article’);

Now this is a great method for local development. It becomes more tricky when you’re dealing with deployments and multiplatform development. As mentioned in the post, “You can not have a symlink like this inside a Git repo, since Git does not handle symlinks cross-platform.” This is fine if you develop on Linux and Mac where the symlinking is the same and you just place it into the postinstall hook. If you develop with Windows then you have to make sure your postinstall script is multiplatform, and don’t even bother trying to create valid symlinks within a Vagrant shared folder.

Overall it just feels like extra work to add and maintain large amounts of symlinks in a multiplatform manner.

The Global

In your app.js:

global.**base =** dirname + ‘/’;

In your very/far/away/module.js:

var Article = require(__base + ‘app/models/article’);

While this may seem like a smart idea for your local module what happens when a module you include and require in also modifies your global scope to use __base? It creates a possible unknown state and it’s overall a very lazy approach.

The Module

Install some module:

npm install app-module-path –save

In your app.js, before any require() calls:

require(‘app-module-path’).addPath(__dirname + ‘/app’);

In your very/far/away/module.js:

var Article = require(‘models/article’);

This is probably the closest method to what I’ve implemented except this messes with require(), personally I don’t like messing with nodeJS super functions as they could change in any version and break many things. If I were to break require it wouldn’t be automatically done it would be a manual choice.

Specifically looking at cwd.js line 6

// https://github.com/jhnns/rewire/blob/master/lib/index.js

  delete require.cache[__filename]; // deleting self from module cache so the parent module is always up to date

It’s specifically tying itself into the require cache to keep itself up to date. It seems hacky instead of the module itself keeping the state. Then again this just creates extra directories to search in.

The Environment

Set the NODE_PATH environment variable to the absolute path of your application, ending with the directory you want your modules relative to (in my case .).

There are 2 ways of achieving the following require() statement from anywhere in your application:

var Article = require(‘app/models/article’);

The article then proceeds to give platform specific ways to extend the environment variable NODE_PATH. Again, it’s platform specific and does solve the issue but not when you want to add/remove more modules. It consolidates the configuration to package.json or whatever script runs your application.

Possibly it can be done in a gulpfile but I prefer to not use gulp for application running. It may also be possible your NODEPATH may conflicts with node_modules, would it be possible include the same module by doing _require(’lodash’) & require(’node_modules/lodash’)? It breaks convention that it looks like a relative path but is actually not.

The Start-up Script

Effectively, this solution also uses the environment (as in 4.2), it just abstracts it away.

With one of these solutions (5.1 & 5.2) you can start your application like this from now on:

Linux: ./app (also for Windows PowerShell)

Windows: app

He gives a solution here.

This specifically is a little worrying as it forks the process for no real good reason. Yes it does create the correct working directory but, again, it forks the process. The OS specific scripts are a better approach but they are OS specific, which defeats the purpose.

The Hack

process.env.NODE_PATH = __dirname;

require(‘module’).Module._initPaths();

Yeah I don’t need to override the NODE_PATH during runtime and then call a private method on Module.

The Wrapper

Place this code in your app.js, again before any require() calls:

  global.rootRequire = function(name) {
       return require(__dirname + '/' + name);
  }

You can then require modules like this:

var Article = rootRequire(‘app/models/article’);

This is probably the best recommendation as it doesn’t explicitly overwrite require and it doesn’t muck around with the private variables. It does however create a new require function on the global scope which could be a problem if another module were to use it.

Conclusion

The Namespacer-js module exists to solve a specific problem of internal module dependencies without having to mess with require or global variables. It creates an easy way to alias filepaths without having to modify NODEPATH and is extensible. Overtime it can be done to create a truly global namespace that included modules (when initially required) can register namespaces and can be pulled in completely decoupled from their original module. Almost as a _component than a bundle.

Related Articles

MoarDammit Beta 2.1.3

5 years ago the project named Moardammit sprang to life and with it brought a whopping 24 swfs hardcoded into the index …

What is Synk?

What? Synk is an application that allows a user to synchronize an action across many patrons in a room. In this case it …