node_modules/.bin/package.cmd file in node js - node.js

I am new to node js. I am trying to build a npm module and confused a bit with cmd file present in /node_modules/.bin folder with the name of the package locally.
I installed multiple packages as dependencies and found that cmd files are different.
jade.cmd
#IF EXIST "%~dp0\node.exe" (
"%~dp0\node.exe" "%~dp0\..\jade\bin\jade" %*
) ELSE (
#SETLOCAL
#SET PATHEXT=%PATHEXT:;.JS;=;%
node "%~dp0\..\jade\bin\jade" %*
)
mocha-casperjs.cmd
#IF EXIST "%~dp0\/bin/sh.exe" (
"%~dp0\/bin/sh.exe" "%~dp0\..\mocha-casperjs\bin\mocha-casperjs" %*
) ELSE (
#SETLOCAL
#SET PATHEXT=%PATHEXT:;.JS;=;%
/bin/sh "%~dp0\..\mocha-casperjs\bin\mocha-casperjs" %*
)
My question is, if it is auto-generated by NPM, why npm creates 2 different files for 2 different packages. Is is something a user creates and tells NPM?

tl;dr
On Windows, npm creates the wrapper batch file (*.cmd) based on whatever shell/interpreter is specified in the script file's shebang line.
What you're seeing is npm's emulation of the Unix shebang mechanism for Windows, where the very 1st line of an executable plain-text file (script), if it starts with magic characters #!, tells the OS what interpreter/shell to pass the script to for execution (see this answer of mine for more information).
Since Windows doesn't support shebang lines, npm creates a wrapper *.cmd (batch) file, that explicitly invokes the "binary" file (the script file specified in the bin key of package.json) with whatever executable is specified in the script file's shebang line.
In other words: npm parses the script's shebang line to determine what shell/interpreter to invoke, and creates the wrapper batch script accordingly.
If we peek at ./bin/jade.js inside the jade package, we see #!/usr/bin/env node as the shebang line, which is why the jade.cmd wrapper file invokes node.exe.
This is the typical case: a script written in JavaScript that must be executed by the Node.js engine.
However, any other shell/interpreter may be specified too, but doing so only makes sense if a given shell/interpreter is also available on Windows; for node, that is a given, but, as the contents of mocha-casper.cmd shows, it makes no sense with the Unix default shell, /bin/sh (the ./bin/mocha-casperjs file from package mocha-casper.js contains shebang line #!/bin/sh).
The makers of the mocha-casperjs have chosen to roll their own Windows integration by re-implementing the Unix shell script for cmd.exe as mocha-casperjs.bat (also a batch file) - however, since npm is unaware of this, this batch file is not placed in the PATH (global) / not discoverable by name only (when calling CLIs in a project context).
More generally, for scripts to also work on Windows, it doesn't make sense to use shebang lines with absolute, POSIX-style paths - EXCEPT if the target shell/interpreter is specified by indirect invocation via /usr/bin/env, which signals to npm that it should be looked for in the PATH (again, see this answer of mine for more information).
(Additionally, the wrapper batch files also look in their own directory for the executable, but that is rarely helpful, given that npm wouldn't copy them there even if you explicitly added them as an entry in your package.json's bin key.)
As an aside: recent versions of npm also create extension-less wrapper scripts for Unix environments, notably Cygwin, and Bash on Ubuntu on Windows.
When creating your own packages, for CLIs ("binaries") - directly executable scripts that act like command-line utilities - that are part of an npm package to work on Windows too, you must:
Add a shebang line to your scripts - even if you only ever intend to run them on Windows.
Define that shebang line as #!/usr/bin/env <interpreter-executable-filename-without-extension>; typically - if your script is written in JavaScript and must be executed with node - use:
#!/usr/bin/env node
In your package.json file's bin key, define the script's key without extension., because .cmd is directly appended to the key name when the wrapper batch file is created (on Unix, a symlink is created named for the key as-is); e.g.:
"bin": { "foo": "./bin/fooj.js" }
Caveat: If the script pointed to by the bin key in package.json has extension .js but has no shebang line, the wrapper script will invoke the .js file directly, which will by default execute it with WSH (specifically, with JScript, its JavaScript engine) rather than Node.js, which won't work as intended - see this question for what symptoms you would see.

You can tell npm to make executable file provided with your package accessible from ./node_modules/.bin directory (in case of local install) or globally (when module is installed globally). You should place bin field into package.json and specify relative path to script. For example, jade package.json contains the following code:
"bin": {
"jade": "./bin/jade.js"
}
When installing jade package, npm makes this script (./bin/jade.js) accessible by generating, if neccessary, wrapper script (jade.cmd) which contents depend on current OS, shell, and the type of script you wish to make accessble. Jade uses .js script, and npm generates jade.cmd for your OS that will launch node and pass script name as argument. But mocha-casperjs uses shell scripts, so contents of generated mocha-casperjs.cmd are different — it starts sh.exe instead of node.
You can read about bin field of package.json here: https://docs.npmjs.com/files/package.json#bin

Related

How can I suppress “Terminate batch job (Y/N)” confirmation in PowerShell?

When I press Ctrl+C in PowerShell, I receive:
Terminate batch job (Y/N)?
Similar to https://superuser.com/questions/35698/how-to-supress-terminate-batch-job-y-n-confirmation, except for Windows PowerShell.
Does PowerShell provide any more control over batch jobs than what CMD does?
The behavior is neither caused by PowerShell nor can PowerShell change it (as evidenced by the PowerShell source-code repo not containing the prompt message).
The behavior is built into cmd.exe - Powershell, in this case, is calling a .cmd file (batch file), which is interpreted by cmd.exe.
If you explicitly control the invocation of the target executable, you can fix this by moving to Powershell - note this has its own considerations, see below.
If you do not explicitly control the invocation of the target executable, you're out of luck (unless you're willing to install third-party cmd.exe replacements) and must press Ctrl+C twice in order to terminate execution.
A[n ill-advised] workaround is to modify the cmd.exe binary - see article with instructions on how to patch the cmd.exe executable in order to suppress the prompt. Additionally, you can post a feature request on GitHub to request that this behavior be fixed at the source, though that is unlikely to happen for reasons of backward compatbility.
To demonstrate the behavior:
The examples assume that Node.js is installed and that node.exe is therefore in your PATH:
First, invoke node.exe directly, with a tight loop that requires you to press Ctrl+C to terminate the process.
PS> node -e "while (true);"
As you'll see, pressing Ctrl+C instantly terminates the process - no confirmation prompt.
Now, let's create a sample batch file that invokes the same command and invoke that batch file:
PS> "#echo off`nnode -e `"while (true);`"" | Set-Content test.cmd
PS> ./test.cmd
As you'll see, pressing Ctrl+C now presents the undesired Terminate batch job (Y/N)? prompt. (You'd get the same behavior if you ran the batch file from cmd.exe.)
To demonstrate that gulp is a cmd file:
You say you're running your command via gulp's CLI.
On Windows, the entry point for the gulp CLI is gulp.cmd [see update in the bottom section] - i.e., a batch file. That is how it works in general for npm-package "binaries" (executables) implemented as either JS files or shell scripts.
That gulp invokes gulp.cmd can be verified as follows:
# Execute from a project folder that has `gulp` installed as a dependency.
# If `gulp` is installed *globally*
# Note: CLI `npx` requires npm version 5.2.0+
PS C:\some\NodeJs\project> npx where gulp
You'll see something like:
C:\some\NodeJs\project\node_modules\.bin\gulp
C:\some\NodeJs\project\node_modules\.bin\gulp.cmd
Note that where.exe also lists the extension-less Unix-shell script, ...\gulp; however, from cmd.exe / Powershell such a shell script isn't directly executable, and it is ...\gulp.cmd - the batch file - that is executed.
(If in doubt, place a command such as #set /p dummy="Press a key" at the start of the gulp.cmd file, and you'll see that this command executes when you invoke gulp without the .cmd extension.
Also note that there is no gulp.exe.)
More generally, on Windows, a project's node_modules\.bin subfolder contains pairs of CLI entry points for the CLIs that come with packages that the project depends on locally:
node_modules\.bin\<some-cli> is the Unix shell script (whose executing interpreter is controlled via its shebang line).
node_modules\.bin\<some-cli>.cmd is the helper batch file for Windows.
Updates and future considerations:
In the context of npm modules, the problem would go away if a PowerShell script (*.ps1) were used as the helper script on Windows. There are tickets for npm, yarn and similar software to do this. There are also some drawbacks:
*.ps1 files aren't directly executable from outside of PowerShell, notably from cmd.exe and File Explorer (and changing that is nontrivial).
PowerShell still hasn't fully replaced cmd.exe as the default shell, as of Windows 10 (and won't anytime soon, if ever).
When called from PowerShell, a *.ps1 file would be found and run in-process, so a possible solution is for the npm project to also provide *.ps1 helper scripts, which would take precedence over *.cmd files of the same name.
Update:
Recent versions of npm (verified in 6.14.10) indeed DO install such *.ps1 files.
Alternative package manager yarn, since v2 does not seem to use batch files anymore at all, so the original problem is bypassed there; (v1, by contrast, still uses batch files (only); upgrading from v1 must be done on a per-project basis see the migration instructions).
As the other answer notes, the correct fix is to replace cmd scripts with ps1 versions.
However another workaround for users of the Hyper shell is 'Hyper yes', a plugin that automatically hits y for you when the prompt comes up.
best way to avoid it is to not start it, in my case, is not to type npm run devStart but instead type nodemon ./server.js localhost 3000
here's how it looks like
#echo off
start /w "" "C:\myfile.bat" 2>nul|findstr /i "termin"
if errorlevel 1 goto bypass
:bypass
echo hello by stexup YouTube channel!
timeout /t 5 >nul

how to install different files for different platforms

I'm building a command line tool using node/javascript, and want to make it available as an npm module. The tool requires a wrapping shell / windows batch script, but how do I install different scripts for different platforms? In package.json I have
"bin" : {
"lookup-bat" : "./bin/lookup.bat",
"lookup-sh" : "./bin/lookup.sh"
}
but I would like to have the same command name, regardless of platform. Is this possible?
Usually you don t mind about that.
Usually, ./bin/lookup is a js file starting with the appropriate shebang #!/usr/bin/env node.
NPM does the rest.
If the program behavior needs to be different for the runtime OS, you shall implement a sort of if(process.platform.match(/win/)) within your program.

setting environment variables for node.js child process

I have a node webkit app, part of which involves using child processes in node to call pdftk (a separate command line program).
I don't want my users to have to install pdftk or use the command line, so I included pdftk in the packaged version of the node webkit app. If I run this packaged app from the command line, it works fine - and I assume that's because it's using the version of pdftk that's installed on my computer, not the one packaged with the app.
When I try to launch the app by double clicking on an icon in the gui, as I'd want a user to be able to do, I get a node.js error - child process ENOENT. I think that's because when launched through the gui, it doesn't inherit the environment variables (including PATH) from my command-line environment.
I know I can set environment variables as an option when I call the child process, but haven't been able to figure out how to do that correctly. I'm not sure what variable I should set, or what I should set it to. I suppose I'm not sure if it's even possible to call pdftk from within the packaged app, or if I would need to have the user install it on their own computer. Any help would be much appreciated.
I think this might not be about environment variables. I guess when you run from the command line your current working directory (CWD) is where the app is. And I think you set the path to pdftk relative to the node script. When you double click (a shortcut) the current working directory and the path where the node script is located are different so relative paths don't work as expected.
When you use relative paths, always use __dirname to get the path the node script is on and use it to set path to the pdftk file. The path.resolve function can be useful when doing this. Read path.resolve documentation
I strongly recommend you to check this question and answers
How do I get the path to the current script with Node.js?
What is the difference between __dirname and ./ in node.js?

Running node.js code just displays a node identifier

I have the following code in a file called server.js.
var http = require('http');
http.createServer(function (request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end('Hello World\n');
}).listen(8124);
console.log('Server running at http://127.0.0.1:8124/');
I use the command prompt and naviage to the folder where the file recides and then the run the command
node server.js
But I don't get the expected output. Instead I get
The node identifier for {My Machine Name} is v2hrfnqaj.
Note: I already have node installed in my machine and it was working fine.
Was getting this when I was trying to run cordova commands. Steps to resolve:
Windows
In CMD prompt, type "where node". As Michael mentioned, this shows
you the likely culprit, that you have 2 nodejs EXEs installed on
your machine.
Navigate to Start > Computer > Right-click Properties > Advanced system settings
Under the Advanced tab, select Environment Variables
Under System variables, select "Path" variable
Find nodejs EXE, usually "C:\Program Files (x86)\nodejs\"
Cut and paste this to the beginning of the "Path" variable. Ensure
the paths are separated by a ";"
Open a new CMD prompt and try cordova again
This happens when Harvest SCM is installed on your system. It has an executable with the name node.exe at <Program Files (x86)>\CA\SharedComponents\PEC\bin (where <Program Files (x86)> is your x86 program files folder). This path is present in your PATH variable before the path to Node.js's node.exe.
Update: You don't need the elaborate scheme listed in the old answer. You just have to open the Command Prompt and run:
C:\> nodevars
nodevars.bat is a small script that does essentially the same thing described below (but in a safer way). If you have node installed, this script should be in path. (If not make sure to add C:\Program Files\nodejs to your path. But make sure to append it in the end so Harvest SCM does not break).
Everything below is outdated, but I will leave it for the curious reader.
You can do either of following two things you can do to overcome this problem:
Remove <Program Files (x86)>\CA\SharedComponents\PEC\bin from PATH environment variable.
Add/move <Program Files (x86)>\nodejs to the beginning of the PATH environment variable (This is the currently accepted answer from djrpascu).
You can do better!
There are two problems with the above approaches:
You break Harvest SCM's functionality.
If you do not have elevated privileges to change PATH, you are out of options. (Thanks #Glats)
So I created this little batch file, and put it in a directory where I have several other personal scripts (this directory is in my PATH). Here's the gist for the script.
nodecmd.bat
#echo off
set path=%path:C:\Program Files (x86)\CA\SharedComponents\PEC\bin;=%;C:\Program Files (x86)\nodejs;
start %ComSpec%
Then the next time you want to run Node.js, instead of Command Prompt, you open the new script with "Run..." command.
Windows+R
nodecmd
A command prompt will appear. You can use this command prompt to run node without a hassle.
Explanation
This bit deletes the Harvest's executable's path from PATH variable:
%path:C:\Program Files (x86)\CA\SharedComponents\PEC\bin;=%;
And this adds the Node.js's path:
set path=...;C:\Program Files (x86)\nodejs;
The result is a string that contains the original PATH variable minus Harvest's path, plus Node's path. And it is set as PATH variable in the scope of current batch file.
Note: You might have to change the path's in the script to suit software installation folders in your system).
Next line, start %ComSpec% starts a Command Prompt. By this time, the PATH variabe is modified. With modified environment variables, you can run node within this new Command Prompt. The environment variable modification does not affect the rest of the system, making sure that Harvest SCM software runs without breaking.
Don't break your Harvest SCM by removing it from path. Try this one, open your windows command line (cmd) and then pass the following nodejs batch file so that it will set your command line to nodejs environment. Enjoy the node commands there.
C:> "C:\Program Files\nodejs\nodevars.bat"
You can also prioritize in the environments.
Steps:
Computer -> Right click -> Properties -> Advanced system settings -> Environment variables -> PATH(in system variables list) -> Edit -> Prioritize by moving up
This is old, but I ran into this same problem. Exact same message (with my machine name of course). The issue was that there was another node executable on the path, in C:\Program Files (x86)\CA\SharedComponents\PEC\bin. I'm on a windows machine, so running where node showed the two conflicting "node" executables in the path.
To fix the problem, I just removed the CA directory from the PATH environment variable.
I faced the same problem and simply changed the the name of node.exe file from Harvest. This hasn't broken anything from Harvest and I can keep working with it.
Change the Harvest's command name to node_.exe:
ren "C:\Program Files (x86)\CA\SharedComponents\PEC\bin\node.exe" "C:\Program Files (x86)\CA\SharedComponents\PEC\bin\node_.exe"
I think you're running the wrong node command.
Try locating or re-downloading your nodejs installation and add it to your path as the first directory. If you're running linux or unix you can try 'which node' to see what is being run.
Note that in some cases, the node.js executable is called nodejs so you may want to try
nodejs server.js as well
I used the node.js command prompt, instead of the windows default command prompt and it worked for me. Did not know why it did't work in the windows default command prompt.
I was also running with same issue - while defining the path for windows use below parameter
Windows:
set NODE_PATH=C:\nodejs
OR
Set the environment variable for nodejs
NODE_PATH=C:\nodejs
Path= C:\nodejs
(append the path contain this string “c:\nodejs”)

CLI with nodejs

I'm developing a CLI in node that will be published to NPM.
Since it's a CLI application, I want it to be included in the path once it's installed, so it's not require to type "node my-app.js" to run it. I want it to run with only "my-app".
In the package.json, I'm including:
"bin": {
"my-all" : "./my-app.js"
},
But this makes fail the installation via NPM with this error
Error: ENOENT, chmod '/home/user1/node_modules/my-app/my-app'
Assuming you're on some kind of unix (linux, osx), put this line at the top of your script:
#!/usr/bin/env node
Also make sure you set the file to executable (chmod a+x my-all).
That should take care of the need to type node my-app.js, and enable you instead to just type ./my-app.js.
As for the npm packaging stuff I am not sure why it fails, but I'm guessing it's an issue with the path or location of your my-app.js .
If an executable script is put anywhere in the PATH, then it will be run just like anything else. If you run which npm, you will see where the npm executable script is located. On my system, most node executable (or executable npm scripts) goes into /usr/local/bin. I'm assuming your package.json can be set to put it somewhere in the path. If you need to change the path, then modify your .profile, or alternatively your system path.

Resources