npm package.json bin won't work on Windows

2019-04-19 22:57发布

问题:

I am trying to start my cli tool via the package.json bin property.

I have the following:

...
"name": "mycli",
"bin": "./bin/mycli",
...

When I open the cmd in the package path and type: "mycli" it says that the command is not recognized.

Should I run an npm command? or use the scripts property? am I trying to access the bin property incorrectly?

回答1:

Try to specify the name of your cli tool in the bin property, like:

"bin": {
  "mycli": "./bin/mycli" // or "/bin/mycli.js" if it's a .js file
}

Then, run npm link, from inside your project folder, to create a global symbolic link to the current folder.

Don't forget to add the "preferGlobal": "true" property just before the bin property in your package.json file, in order to warn users to install your module globally.



回答2:

Whenever I was trying to get my app to link, I kept running into problems on Windows where the generated scripts that would execute on path would try to run the *.js file using the default Windows executable (I don't know what that would be). I'm not sure why. I think it might be because it is a JavaScript file. However, I compared the generated scripts to some of the other modules I had installed, and figured out that if I made the bin file referenced by the package.json act as though it were to be executed on a *nix machine, npm would automatically try and add the call to node.

For example:

If my package.json looks like this:

myapp/package.json

"name": "myapp",
"bin": {
    "myapp": "./bin/myapp"
}

My referenced bin file looks like this:

myapp/bin/myapp

#!/usr/bin/env node
require("../server.js");

The 2 generated executable files that appear in %APPDATA%\npm show up as follows by running the command npm link from within the myapp directory (which would have package.json in the root):

myapp

#!/bin/sh
basedir=`dirname "$0"`

case `uname` in
    *CYGWIN*) basedir=`cygpath -w "$basedir"`;;
esac

if [ -x "$basedir/node" ]; then
  "$basedir/node"  "$basedir/node_modules/myapp/bin/myapp" "$@"
  ret=$?
else 
  node  "$basedir/node_modules/myapp/bin/myapp" "$@"
  ret=$?
fi
exit $ret

myapp.cmd

@IF EXIST "%~dp0\node.exe" (
  "%~dp0\node.exe"  "%~dp0\node_modules\myapp\bin\myapp" %*
) ELSE (
  node  "%~dp0\node_modules\myapp\bin\myapp" %*
)

Bear in mind, I didn't need to make the 2 files above explicitly, I just needed to have the file to be executed as the bin file in the package.json. npm did the file creation.


Line Endings

One other thing to note that I ran into while using this method, make absolutely sure that your line endings are correct. I noticed that my bin was erroring with: ": No such file or directory" whenever I installed on *nix machines because there was an incorrect line ending. Thanks to View line-endings in a text file for example of how to print visible line endings.

For example, if you run cat -e PATH_TO_BIN and get something like this:

#!/usr/bin/env node^M$
^M$
require("../index.js");^M$

You're using the wrong line endings. If you get something like this:

#!/usr/bin/env node$
$
require("../index.js");$

Those should be the right line endings.



回答3:

Answer from Rodrigo Medeiros works for me, but only if I have too the shebang line at the .js file.

There I had another issue. I have node.js installed at c:\Program files\nodejs, and this was my shebang line:

#!c:/program files/nodejs/node

This didn't work, because the blank space. This was the correct one:

#!c:/progra~1/nodejs/node


回答4:

If you put

#!/usr/bin/env node

in the first line of your script, npm will create the necessary wrapper scripts.