61

I'm developing a node package that needs to be run from shell. I know I have to install the package globally, but running

$> npm install -g ./my_module

Does not give me the desired result, that is running

$> my_module

Results in

my_module: : command not found

Instead of running the entry point (index.js) of my node package.

I feel like I'm missing something obvious in here, what am I doing wrong?

Kuba Orlik
  • 3,360
  • 6
  • 34
  • 49

3 Answers3

59

Please try to pack the module and install.

npm pack

and then install it globally

npm i -g my_module-0.0.1.tgz

Let me know is this worked or not

sathishkumar.T
  • 649
  • 1
  • 6
  • 9
  • 6
    `npm link` is useful when you want to debug, while developing. But once its been fully tested I think this solution is appropriate. – aemonge Jul 28 '20 at 15:18
59

After setting up the right package.json configuration, (mainly using {"bin": {...}}), You don't have to publish it to NPM registry then download it again to see it working.

npm link made exactly for this situations. as described in the offical documentation:

npm link in a package folder will create a symlink in the global folder {prefix}/lib/node_modules/ that links to the package where the npm link command was executed.

Assuming you have this project:

-- my_module

-- -- index.js
-- -- cli.js
-- -- package.json

and you have this package.json:

{
  "name": "my_module",
  "bin": {
    "my_module": "cli.js"
  },
}

Run:

cd my_module

Then:

npm link

Now npm will install your package globally in your machine. it will check the package.json for the bin entry, and it will link my_module to the cli.js file. This will happen by creating a symlink in the global npm directory to your current directory.

now if you run in your command line:

my_module

it will point to the cli.js file. if you changed cli.js contents, it will be reflected the next time you run my_module, if you renamed my_module to my_module2, use npm unlink then npm link again.


On a different note, npm can use a full url as a package name, it will use the full url to download and install the package instead of looking at the npm registry, you can install packages from your own private Git hosts, for example:

npm install -g https://github.com/Me/my_module
Thibault Walterspieler
  • 2,272
  • 2
  • 15
  • 25
MohannadNaj
  • 1,029
  • 13
  • 12
  • Hello Mohannad, is it valid to use: npm install -g . ?? – chamix Jul 09 '20 at 21:45
  • prefereGlobal is now depracted ([https://docs.npmjs.com/cli/v6/configuring-npm/package-json#preferglobal]) – Thibault Walterspieler Mar 10 '21 at 11:14
  • npm link worked for me. that and having the bin in the package json. took me awhile to finally get the correct google search keywords to get here. Thank you for this knowledge. – PAT-O-MATION Aug 30 '21 at 22:07
  • I've had issues with npm link using ng-packagr for library development (Angular 12 tbe). I thought it may be related to me using nvm-windows, but after removing it and installing node "normally" the issue persists. So I guess for library development with ng-packagr we are limited to using "npm pack" and installing from archive :/ I hope someone corrects me if I'm wrong. – Michał Knapiński Mar 07 '22 at 10:47
  • @MohannadNaj, Thank you very much! `npm link` option worked perfectly for my case – ddsultan Mar 21 '22 at 14:02
  • for some reason this does not work for me. I followed your instructions and with `npm ls -g` it even shows up with `+-- my_module@0.0.2 -> .\E:\work\my_module` but when I run my JS with `node my_script.js`, that requires "my_module", I still get "Error: Cannot find module 'my_module'". What can be the reason for this? I found a post where it turned out the "main" entry in the modules's package.json was pointing to a non-existing file, but this is not the case here; the main file exists and is correct. – iko79 Aug 01 '23 at 14:59
5

I faced the same issue recently. I developed my module as a CLI with the intent to be able to invoke it from anywhere, published it to the NPM registry and installed it using the -g option but when calling it from the command line I was still getting the command not found error. Adding the bin attribute to the package.json file is what did the trick.

From the NPM documentation:

A lot of packages have one or more executable files that they’d like to install into the PATH. npm makes this pretty easy (in fact, it uses this feature to install the “npm” executable.)

To use this, supply a bin field in your package.json which is a map of command name to local file name. On install, npm will symlink that file into prefix/bin for global installs, or ./node_modules/.bin/ for local installs.

Meaning your package.json file should look like this:

{
    "name": "foo-cli",
    "version": "1.0.0",
    "description": "A CLI to do Foo-ish things.",
    "bin": {
        "foo": "./cli.js"
    },
    "main": "main.js",
    ...
}

The property can be a single string if you only wish to specify one single command, or a map if you wish to specify many. Now you should be able to call foo from anywhere in the command line.

Community
  • 1
  • 1
Mig82
  • 4,856
  • 4
  • 40
  • 63