NodeJS local modules for complex application structures

2.9k views Asked by At

I'm currently part of team building a Windows 8 application using JavaScript. We are using npm and browserify to manage dependencies and convert our modules to AMD browser friendly format.

One issue we are running into is crazy require paths. This is because we have a top level folder inside our application "components". This folder contains a bunch of nested ui components/modules. These modules sometimes require lib utils and helpers, which reside in the lib directory.

So for example, a module living in "my/app/components/product/grid/item" might require a helper module which is located "my/app/lib/helpers/view".

The require path is a bit crazy and very ugly: require("../../../../lib/helpers/view");

We are doing a best to build in application in modular fashion. Now I would think the proper way to approach this is to have our components modules depend on these util helper modules. I could put the lib helpers into their own external private git repo, but that has been pain in terms of giving other teams access (plus git private repos are slow). Plus since those modules are only used in the application, it's a waste of time to make the change, push the changes, then go back to the application and npm update. This is fine for some, but if we really break this down, it could get old real fast.

I could do npm install "my/app/lib/helpers/view" inside the components package.json ? But npm install won't automatically do this for us.

I know of a few other ways around this (NODE_PATH, maybe use a npm install hook or maybe npm preinstall script), but wanted to know if anyone else had a similar problem and good solution.

3

There are 3 answers

2
Gabriel Llamas On

The problem of the require() function is that the paths are relative from the current file. You could put your modules inside the node_modules directory but this is the worst thing you could do. node_modules is the directory where live all the third-party modules. If you follow this simple rule it's very easy and handy to stay always up to date, you can remove all the dependencies (removing the node_modules) and just doing npm install.

The best solution is to define your own require function and make it global. For example:

Your project structure is:

my-project
| tools
|- docs
|- logs
|- conf
`- src
   |- node_modules
   |- package.json
   |- mod.js
   |- a
   |  `- b
   |     `- c.js
   `- d
      `- app.js

mod.js

global.mod = function (file){
  return require ("./" + file);
};

app.js

//This should be the first line in your main script
require ("../mod");

//Now all the modules are relative from the `src` directory
//You want to use the a/b/c.js module
var c = mod ("a/b/c");

That's all, easy. If you want to get a third-party module located in node_modules use require(). If you want to get your own modules use mod().

And remember, node_modules is only for third-party modules, rule nÂș1.

1
jcreamer898 On

One thing you could possibly do is create an alias for your helpers in your require config...

require.config({
    paths: {
        "helpers": "my/app/lib/helpers"    
    }
});

That would cut down on some of your long paths.

5
substack On

You can put your "my/app/components/product/grid/item" files into node_modules/grid/item.js and then when you require('grid/item') in your application code you will get the file you want with a much terser require path syntax. Just check node_modules/grid/item.js and whichever other files into git. The node_modules/ directory need not even be at the top-level since the require algorithm used by node and browserify will search for node_modules/ directories from the current path all the way down to / until it finds a matching module.

Just make sure to add "grid" to the "bundledDependencies" array in your package.json so you don't accidentally install something over it.

You can read more about checking node modules into git.

Read the section of the browserify handbook about avoiding ../../../../../../ for more information.

NODE_PATH is always a bad idea and browserify doesn't support it. Don't ever use it ever.