Today one colleague explained me how to create nodejs projects and I notice that in ./node_modules there is an invisible folder named .bin. I must said that I discovered this after adding to the project "bootcamp" and "bower" tools. What's .bin purpose? What is it created for?
That is a folder where binaries (executables) from your node modules are located.
NPM site states:
Executables When in global mode, executables are linked into
{prefix}/bin on Unix, or directly into {prefix} on Windows.
When in local mode, executables are linked into ./node_modules/.bin so
that they can be made available to scripts run through npm. (For
example, so that a test runner will be in the path when you run npm
test.)
The directory node_modules/.bin is where the binaries of the modules used by your project are stored, normally using symbolic links to the respective binaries in the corresponding module's directory. For example, that is how I see the binary standard from the npm package standard (JavaScript style guide, linter, and formatter)
$ ls node_modules/.bin/standard -l
lrwxrwxrwx 1 jfolpf jfolpf 22 jul 17 08:29 standard -> ../standard/bin/cmd.js
When I run node_modules/.bin/standard I am indeed running node_modules/standard/bin/cmd.js from the npm package standard. This symbolic link was created upon the installation of the package, that is, upon npm install standard
These binaries also allow you to use modules directly from npm scripts. For example, you may not have installed standard globally with npm install standard -g, which means that you cannot run standard directly from your terminal on your module's main directory.
But you can write an npm start or npm test script by adding the following, respectively, to your package.json:
"scripts": {
"start": "standard src/*.js",
"test": "standard src/*.js && node myTest.js"
}
and this is completely correct given you have standard as the project dependency. Even though the module is not global and not usable by the operating system directly, npm can look for the bin folder for the given standard module name and trigger the compiled binary. So indeed, npm runs such a script :
"start": "node_modules/.bin/standard src/*.js",
Related
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
Created new folder and did npm install serve in it.
It created package-lock.json and node_modules/ folder.
When I run in the same folder serve it shows error:
command not found: serve
What is the way to install?
I am using: npm#6.5.0
My dev environment is MACOS
I read a great many pages on this topic and nothing worked until I tried the following
./node_modules/.bin/serve -s build
Also if you are using VS CODE you may want to bring up the terminal window outside of VS CODE - this seems to have snared a lot of people.
First of all, you should start your project running
npm init
This will create the package.json file.
Then, you can install the serve package globally.
npm install -g serve
And now you can run serve.
The serve binary was not found because the operating system cannot locate it in the PATH environment variable.
When you do the npm install serve command. The serve module is only installed into the node_modules directory found under the the project folder. Unless you explicitly include the absolute path of this node_module directory as part of your PATH env var, the OS won't know where to find serve.
Like others say, the typical practise would be to install the module using the -g flag. G means global.
When -g is used, npm will put the binary in its node directory somewhere and this this directory would have been included as part of your PATH when you install node, thus making the any new binary discoverable.
If the node.js module has a "command" and you want to run it without installing the module globally(npm install -g serve). You can run it like ./node-modules/.bin/command from the root folder of the project.
Now, what is generally used is npx, so that you can from within a project easily run any of the binaries within its local node_modules or your system's global node_modules/ and any other commands on the $PATH.
For example, here we install webpack as a local dependency. You can image doing this in a folder after running npm init. Then we run webpack without having to worry about referencing the bin file:
$ npm i -D webpack
$ npx webpack
I read on the npm documentation that you can't use bin scripts of locally installed packages.
So, how gulp can be launched as bin command when installed locally?
What's making it available when locally installed, I reviewed the gulp package.json and the bin scripts, I don't found any answer.
From NPMJS documentation:
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.
So, your locally installed packages binaries will be executable like this
./bin/node_modules/.bin/the_binary
This is if you want to launch the binary directly. Or, as specified in the scripts part of the documentation:
In addition to the shell's pre-existing PATH, npm run adds node_modules/.bin to the PATH provided to scripts.
Thus, you can simply write a wrapper script like
scripts: {
"build": "the_binary"
}
and call your script like this
npm run build
Bonus
As of npm#2.0.0, you can use custom arguments when executing scripts. The special option -- is used by getopt to delimit the end of the options. npm will pass all the arguments after the -- directly to your script:
npm run test -- --grep="pattern"
You can use lpx https://www.npmjs.com/package/lpx to
run a binary found in the local node_modules/.bin folder
run a binary found in the node_modules/.bin of a workspace root from anywhere in the workspace
lpx does not download any package if the binary is not found locally (ie not like npx)
Example : lpx tsc -b -w will run tsc -b -w with the local typescript package
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 do you create a console app that you can run by a name instead of using node and a .js file to start the app?
Instead of...
$ node myapp.js --out ./folder/
Can I...
$ myapp --out ./folder/
You can use the bin option in your package.json file to make your script executable. From the documentation for package.json:
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.
Click the link and search for bin: https://www.npmjs.org/doc/json.html for more info.