Avoiding require('../../../relative/path') hell in Node.js

A frequent problem that you might run into in your Node.js application is requiring your local dependencies using a relative path notation. I.e., similar to require('../../../config/app'). This can soon become confusing, error prone and a huge productivity loss trying to hit the right level of directory structure.

The most elegant way that I have come across so far is an npm package module-alias.

With the package installed, I can then configure aliases like @app and @root that makes local dependency locations manageable and much more pleasant to interact with.

To configure, install the package as usual:

npm i module-alias --save  

As the first line of your program entrypoint, i.e, index.js or server.js, register the package:

require('module-alias/register')  

Aliases are defined in package.json, as follows:

  "_moduleAliases": {
    "@app": "./src",
    "@root": "."
  },

This setup now allows you to refer to your local dependencies as:

const userRoutes = require('@app/routes/user')

// or using import
import User from '@app/models/User'  

That works for your server-side application. What about client? Fortunately, this package can also be used with Webpack, which allows use of alias via its resolve configuration. An example configuration webpack.config.js snippet is below:

const packageJson = require('./package.json')

let webpackConfig = {  
  // ...
  resolve: {
    alias: packageJson._moduleAliases
  },
  // ...
}

This pulls in the same alias definitions from package.json. From that point, you can refer to client-side dependencies also with the same @app/path/to/file syntax.

If you are using less-loader with Webpack resolver, the syntax for @imports are as below example (Note the preceding ~, which enables less-loader version 4 and above to resolve using Webpack's resolver):

@import (reference) "~@app/styles/mixins/buttons.less";

Hope that helps. If you are aware of a better pattern, please share via comments below.

comments powered by Disqus