Install a locally developed npm package globally - node.js

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?

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

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

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.

Related

What's the difference between "npm install -g" (no args) and "npm link" to create CLI command?

To make a local node.js package work as a global commandline tool, I first add this to package.json
"bin": {
"myCommand": "./index.js"
}
According to the npm docs, I then have two options:
Within that folder, run npm install -g. According to the node docs:
npm install (in package directory, no arguments) ... In global mode
... installs the current package context (ie, the current working
directory) as a global package.
OR
Within that folder, run npm link. The node docs say
npm link in a package folder will create a symlink in the global
folder ... will also link any bins in the package to
{prefix}/bin/{name}
Both of these routes lets me run myCommand anywhere in the terminal while local edits are reflected in the tool without reinstalling/linking.
For local CLI tool purposes, these commands seem functionally identical. Is this true? Why would I want to use npm install -g (no args) when npm link seems functionally identical, plus affording extra capability?
Note: this question is purely about a local node project, nothing to do with anything in a remote package registry

Locally-installed cli NPM project that is easy to execute

I'm building a cli node module. I would like people to be able to npm install it and use it right away with a command like npm my-project --arg=foo. It's meant for local project CLI use as a dev tool, not global installation.
It seems like the standard is to use bin in the package.json, but I don't understand some things about it:
When should I use bin and when should I use scripts?
How to I run the command in the including project? npm my-project doesn't do it.
Here is what I am doing now in package.json:
{
"name": "my-project",
"bin": "./cli.js"
}
And I can run it locally:
node cli.js --arg=foo
But when I npm-install my-project somewhere else, I don't know how to run the script it puts in bin (npm run my-project doesn't work), or if I'm using this correctly.
Let's start by explaining the difference between bin and scripts: the former you use if you want to provide a command line tool, the latter you use if you want to provide an additional command to npm (with some caveats though, see below).
In your situation, I think you want to use bin. However, instead of the user using npm my-project --arg=foo, they will use my-project --arg=foo, provided that your script is called my-project. To make that happen, your package.json will contain something like this:
"bin" : "./bin/my-project"
During installation, this will copy ./bin/my-project to a "bin" directory (usually /usr/local/bin on Unix-like OS'es). During development, you can call it as node bin/my-project, or even just ./bin/my-project, provided that it has correct permissions and "shebang".
EDIT: so I forgot that npm will use the package name, and not the name of the file in ./bin, as the executable name (if bin is a string). If your package is called my-project, and you install the package (you need to use the -g flag before npm will install the executable), it will create an executable called my-project, regardless of where the bin property points to.
In other words:
package.json:
"name" : "my-project"
"bin" : "./cli.js"
npm install -g:
copies ./cli.js to /usr/local/bin/my-project and sets executable permissions
END EDIT
FWIW, storing CLI tools in ./bin is convention, but not mandatory.
The scripts directive is useful for more internal purposes. For instance, you can use it to run a test suite, or linters, or pre/post install scripts.
Lastly, there are various modules available to help with command line parsing. I like docopt, but other often-used modules are commander or nomnom. You already mentioned yargs.

How can I run a script from an already installed NPM package?

Example:
npm install my-tools
npm run my-tools tool1
This doesn't work - it looks for a "package.json in my current directory. The documentation for "npm run" says:
If no package name is provided, it will search for a package.json in
the current folder
(https://docs.npmjs.com/cli/run-script)
So how can I provide a package name?
It looks like you're trying to run a script defined in the package.json of my-tools. This functionality is not supported as of npm#2.0.0.
The reference to npm run-script taking a package name is a documentation error; I have created an issue for that on the npm issue tracker: https://github.com/npm/npm/issues/7440
Some alternatives might include:
using npm explore to temporarily set current directory (etc.) into the package, e.g., npm explore my-tools -- npm run tool1
publishing tool1 etc. as bin entries in package.json instead of as scripts; this will make them accessible via the command line
depending on your needs, you may find a more heavyweight task runner such as grunt is a better approach than npm scripts and binaries

How to put local node package on path?

Newbie question. I have chosen not to install express with -g option. I did not use npm -g which would put it on the path globally. Instead it is installed in my local mac user directory. What I am not clear on is exactly what or how you put a package like express on the path so it can be invoked etc? What exactly needs to be on the path (node_modules?) so these packages are available just like a -g installation? I could have used home-brew I suppose but anyway, I now have all node packages and everything local. Another situation is that I am not able to run any of the nodejs tutorials. Although there might be smarter ways to do this, I wonder if sudo is really such a good way to install a development package ....
Now for example, I want to run the tutorial javascripting which is a nodejs tutorial. How do I do this. If I just type:
Mac1$ javascripting
it finds nothing.
Same for
Mac1$ express
UPDATE: THIS WAS ANSWERED IN THE COMMENTS
The commands exist in a hidden directory after a regular
install npm install express
in my case this the command goes here: /users/MAC1/node_modules/.bin
It is this path that needs to be placed on the $PATH as described in the first comment.
Thanks guys.
npm installes executable to two places. By default running a npm install in a project will install any binaries in ./node_modules/.bin. When you use the -g flag (npm install -g package-name) it will install into a global path. You can find out the global path by running npm bin -g. Add that to your path and globally installed executables will be accessible.
You can also add ./node_modules/.bin to your path to allow easy access to executables added by packages in your project folder. I admit to using this on a trusted local machine. However, this is very dangerous and not a recommended way to expose the executables in the node_modules directory.
Best alternative is to add the executable to the scripts section of the package.json file and then use npm run-script <command> which will auto prepend the ./node_modules/.bin when executing.
package.json
{
"scripts": {
"foo": "foo --arguments"
}
}
Example
$ npm install foo
$ ls ./node_modules/.bin
foo
$ npm run-script foo
# Executes:
./node_modules/.bin/foo --arguments

Possible to include a command-line in a Node module without global install?

I have a small Node module that includes a command line script in the bin directory.
"bin": {
"generate": "./bin/generate.js"
}
The generate.js script is properly executable.
This all works fine if I run npm install -g. But I'd prefer not to globally install and only have the command generate work from inside the module folder. If I run npm install from the module folder, it does correctly install all of the dependencies in a node_modules subdirectory. But then generate from the command like gives me "No such file or directory."
Thx.
I never install node modules using -g. My solution for your problem is to add this to my $PATH
# add this to ~/.bashrc, ~/.zshrc, or ~/.profile, etc
export PATH="./node_modules/.bin:$PATH"
Now, so long as your in the root of your module, you can access any binaries that have been installed as modules.
As an example, less is commonly installed with
npm install -g less
However, if you have your PATH modified as described above, you could something like this
cd my_node_module
npm install --save less
lessc less/style.less css/style.css
Without the PATH modification, you would've seen
command not found: lessc
If you don't feel like altering your PATH, you can access the binary directly
cd my_node_module
npm install --save lessc
./node_modules/.bin/lessc a.less a.css
Yay, no more npm install -g ...

Resources