Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save ashokaditya/39e146c073944531a7ff346bbec2b9ab to your computer and use it in GitHub Desktop.

Select an option

Save ashokaditya/39e146c073944531a7ff346bbec2b9ab to your computer and use it in GitHub Desktop.
Better local require() paths for Node.js

Better local require() paths for Node.js

Problem

When the directory structure of your Node.js application has some depth, you end up with a lot of annoying relative paths in your require calls like:

var Article = require('../../../models/article');

Those suck for maintenance and they're ugly.

Possible solutions

Ideally, I'd like to have the same basepath from which I require() all my modules. Like any other language environment out there. I'd like the require() calls to be first-and-foremost relative to my application entry point file, in my case app.js.

TL;DR Warning: I only really like solutions 2, 5.1 and 6, but they all work.

1. The Symlink

Stolen from: focusaurus / express_code_structure # the-app-symlink-trick

  1. Create a symlink under node_modules to your app directory:
    Linux: ln -nsf node_modules app
    Windows: mklink /D app node_modules

  2. Now you can require local modules like this from anywhere:

    var Article = require('models/article');

Note: you can not have a symlink like this inside a Git repo, since Git does not handle symlinks cross-platform. If you can live with a post-clone git-hook and/or the instruction for the next developer to create a symlink, then sure.

2. The Global

  1. In your app.js:

    global.__base = __dirname + '/';
  2. In your very/far/away/module.js:

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

3. The Module

  1. Install some module:

    npm install rekuire
  2. In your app.js:

    global.rekuire = require('rekuire');
  3. In your very/far/away/module.js:

    var Article = rekuire('models/article');

Mind that rekuire will allow you to not specify any path at all, so the file app/a/b/c/d/e/f/my-mod.js can just be loaded like this:

var myMod = rekuire('my-mod');

If you choose rekuire, I advise you to make all paths relative to your app/ directory, to prevent any ambiguity. Like this:

var myMod = rekuire('app/a/b/c/d/e/f/my-mod.js');

Just so you know, rekuire actually handles ambiguity the right way, with a sane error message.

4. 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');

4.1. Up-front

Before running your node app, first run:

Linux: export NODE_PATH=.
Windows: set NODE_PATH=.

Setting a variable like this with export or set will remain in your environment as long as your current shell is open. To have it globally available in any shell, set it in your userprofile and reload your environment.

4.2. Only while executing node

This solution will not affect your environment other than what node preceives. It does change your application start command.

Start your application like this from now on:
Linux: NODE_PATH=. node app
Windows: cmd.exe /C "set NODE_PATH=.&& node app"

(On Windows this command will not work if you put a space in between the path and the &&. Crazy shit.)

5. The Start-up Script

Effectivly, 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

An advantage of this solution is that if you want to force your node app to always be started with v8 parameters like --harmony or --use_strict, you can easily add them in the start-up script as well.

5.1. Node.js

Example implementation: https://gist.github.com/branneman/8775568

5.2. OS-specific start-up scripts

Linux, create app.sh in your project root:

#!/bin/sh
NODE_PATH=. node app.js

Windows, create app.bat in your project root:

@echo off
cmd.exe /C "set NODE_PATH=.&& node app.js"

6. The Hack

Courtesy of @joelabair. Effectively also the same as 4.2, but without the need to specify the NODE_PATH outside your application, making it more fool proof. However, since this relies on a private Node.js core method, this is also a hack that might stop working on the previous or next version of node.

This code needs to be placed in your app.js, before any require() calls:

process.env.NODE_PATH = '.';
require('module').Module._initPaths();

Conclusion

1. The Symlink
If you're using CVS or SVN (but not Git!), this solution is a great one which works, otherwise I don't recommend this to anyone.

2. The Global
You're effectivly swapping ../../../ for __base + which is only very slightly better if you ask me. It does make very clear to the next developer what's happening here. That's a big plus compared to the other magical solutions around here.

3. The Module
The verdict for this one is the same as for solution 2, this is a very nasty hack. Steer clear.

4. The Environment
Setting application-specific settings as environment variables globally or in your current shell is an anti-pattern if you ask me. E.g. it's not very handy for development machines which need to run multiple applications.

If you're adding it only for the currently executing program, you're going to have to specify it each time you run your app. Your start-app command is not easy anymore, which also sucks.

5. The Start-up Script
I'd go for this one (5.1)! Apart from 1-2 (tiny) extra files, no disadvantages here. You're simplifying the command to start your app, and it gives you a nice spot to put your mandatory v8 parameters!

6. The Hack
Most simple solution of all. Use at your own risk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment