8

The npm documentation says this:

  • If you’re installing something that you want to use in your program, using require('whatever'), then install it locally, at the root of your project.
  • If you’re installing something that you want to use in your shell, on the command line or something, install it globally, so that its binaries end up in your PATH environment variable.

I am currently writing --- or, at least, trying to write --- a genuine command line program in node that's intended to be used from the shell. Therefore, according to the above, my dependencies should be installed as global modules.

How do I actually use a global module installed with npm in node? Calling require() doesn't work, of course, because the npm global module directory (/usr/local/lib/node_modules) isn't on the path by default. I can make it working by explicitly adding it to the path at the top of my program, but that's a really lousy solution because it's not portable --- it requires knowledge of where the npm's global module directory is on any given system.

Just to make life even more aggravating, I have some global modules installed via dpkg. These have been put in /usr/lib/nodejs, and they just work. This confuses me, because if global modules aren't supposed to be used for ordinary applications I would expect neither to be on the path; or else I would expect them both to be on the path and requiring global modules to just work everywhere. Having one but not the other seems very odd. What's going on here?

Update: I should point out that this program is just a script, with #!/usr/bin/env nodejs at the top; it's not a formal node module, which is way overkill for something quite this trivial. As the Debian modules are all requireable from such a script, it seems sensible to me that npm's global modules should be requireable too, but I have a feeling that this is a Debianism...

David Given
  • 13,277
  • 9
  • 76
  • 123

3 Answers3

5

Therefore, according to the above, my dependencies should be installed as global modules.

Not quite.

It meant that your module could be installed as a global so its binaries would be available from the shell:

npm install -g your-module
your-module-binary --option etc.

Its dependencies, on the other hand, should be installed following the 1st point, residing in a node_modules directory within your project (generally specified in a package.json so npm can manage them).

But, global modules aren't (normally) available for require. They don't follow Loading from node_modules folders, which npm follows for local modules, and their path isn't typically listed in the NODE_PATH variable for Loading from global folders.

Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
1

So the instructions you have pertain to npm modules, but you are doing local development. Here are some guidelines.

In terms of your source code, you only need 2 types of require statements

var dep = require('somedep')

Use this for any core modules (like fs) and third party modules your library needs that you are including via npm (listing them in your package.json as dependencies). Here you specify an unqualified package name and node finds the module according to its search algorithm.

var mymod = require('./lib/mymod')

Use this for requiring the other modules in your project itself by path relative to the current javascript file.

That's all you have to do to handle your javascript dependencies.

OK, now how do you install your dependencies?

For local development (within your project's source tree), just cd into the project directory and run npm install, which will read your package.json file and install the modules you need in the node_modules subdirectory and all will be well for local development.

If you were to actually publish this as an npm module, other users (and you can be both the developer and one of the "other users"), could install it with npm -g if they wanted to access your project's binary utilities on their PATH which would need to include /usr/lib/nodejs/lib/node_modules, but in that case, the npm -g will handle installing both your code and your project's dependencies all at once.

Here's where you are getting confused.

Therefore, according to the above, my dependencies should be installed as global modules.

You don't need to explicitly install dependencies as globals, only the top-level module you are interested in, which in this case is your project itself. npm will handle the dependencies automatically, which is its primary purpose in life. Your project's dependencies won't be installed globally per say, but rather in the node_modules subdirectory of your project, which WILL be installed globally.

Here's the directories and what lives there:

  • ~/yourproject: local development for your source code
  • ~/yourproject/node_modules: npm modules used by your project during development. Created/populated by running npm install in ~/yourproject
  • /usr/lib/nodejs/lib/node_modules: npm modules (which could eventually include yourproject if you publish it to the npm registry) that are installed globally
  • /usr/lib/nodejs/lib/node_modules/yourproject/node_modules: your project's dependencies will get installed here when you do npm install -g yourproject

You may also find my blog post on managing interpreters and the PATH relevant.

Peter Lyons
  • 142,938
  • 30
  • 279
  • 274
  • Yes, but this only really applies to heavyweight projects, which this isn't: this is, in effect, a shell script, one source file with `#!/usr/bin/env nodejs` at the top. It's going to be stuck in `/usr/local/bin` for other users on the machine to get at. Forcing users to create a local project directory just so they can run this is unreasonable. Given that the script can already get at the Debian global modules with `require()`, why can't I get at npm's? – David Given Sep 25 '12 at 15:50
  • You are confusing users with developers. For users, you publish your module to the npm registry and the users just type `npm install -g yourproject` and they are done. If you mark your shell script wrapper as a binary in your package.json (see `npm help json`), npm will put it in the right place so users can run it. – Peter Lyons Sep 25 '12 at 17:12
  • But I don't have a module, that's my point. There is no package.json and no shell script wrapper. I know that I don't need to have a module to do this because if I'm trying to access the node modules that Debian has installed everything just works. It's just npm's that don't work. I'm beginning to suspect that npm doesn't support this use case and that Debian has fiddled their node setup to explicitly make this work. Does this seem plausible? – David Given Sep 25 '12 at 17:18
  • If you have a node program and you have at least 1 non-core dependency, you should make a package.json to track your dependencies. Do you technically have to? No. But you should because it will avoid confusion and problems. So, figure out exactly what your dependencies are and create a simple package.json to track them. Install them inside your project directory via `npm install`. Now you can create a wrapper script that will cd into your project directory then run node like `cd /path/to/project && /usr/lib/nodejs/bin/node ./program.js`. – Peter Lyons Sep 25 '12 at 20:57
0

Additionally, Node.js will search in the following list of GLOBAL_FOLDERS:

1: $HOME/.node_modules 2: $HOME/.node_libraries 3: $PREFIX/lib/node

hewc
  • 119
  • 6