Can I run a command from package.json bin script? - node.js

Is it possible to run a command from a bin script in a package.json ? I know it expects a path to file and trying to run a command there results in an error upon installation (after publishing to npm). Is it possible to run a command like it is in an npm start ?
Examples:
{
"name": "myscript",
"version": "1.0.3",
"bin": {
"myscript": "app/main.js"
}
}
This will create a symlink from the app/main.js script to /usr/local/bin/myscript
Instead, this is what I want to achieve:
{
"name": "myscript",
"version": "1.0.3",
"bin": {
"myscript": "echo hello world"
}
}
Possible workarounds are also appreciated.

This answer is updated since the old answer was a bit dated and ultimately incorrect. You can now do:
npx myscript

Have you tried running npm link https://docs.npmjs.com/cli/link which would create a link to your binary, then you can just run your script on the command line as myscript.

Related

NPM global install of a package in Windows 10 results in Windows Script Host error

I am following the tutorial for building a cli tool in Node here -- How to Build a Command Line (CLI) Tool in Node.
Environment:
Cmder
Node 9.5.0
npm 6.11.3
Windows 10
I am to the point where it has you create it as a shell cmd and the link it using npm link. Instead of running it in my shell--the same way create-react-app does--it instead errors with a Windows Script Host error:
Line: 1
Char: 1
Error: Invalid Character
Code: 800A03F6
Source: Microsoft JScript compilation error`
When I run where npm, I get:
C:\Program Files\nodejs\npm
C:\Program Files\nodejs\npm.cmd
C:\Users\smkar\AppData\Roaming\npm\npm
C:\Users\smkar\AppData\Roaming\npm\npm.cmd`
But when I run where caph, I get:
D:\Code\projects\cap-hooks\caph.js
C:\Users\smkar\AppData\Roaming\npm\caph
C:\Users\smkar\AppData\Roaming\npm\caph.cmd`
I'm pretty sure the error is because it's trying to open it from the local javascript file on the D drive, but I don't know how to fix it. I'm trying to make a CLI tool for fun/learning, and I want to be able to install the tool globally, but I haven't been able to proceed from here/fix this.
For reference here's the file and the package.json:
package.json
{
"name": "caph",
"version": "0.0.1",
"description": "An automated cli package for generating administrative
tools and components for React projects, written in
React Hooks.",
"main": "caph.js",
"bin": {
"caph": "./caph.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "smkarber",
"license": "ISC"
}
caph.js
#!/user/bin/env node
console.log("Hello World!");
After running npm link, I can use caph in my shell, but it immediately gives me a Windows Script Host error instead of running it in the shell. I have tried numerous Github issues returned from Google as well as a handful of Stackoverflow questions, but nothing seems to directly refer to fixing this situation, and I am unable to rectify the situation.
It must be /usr/ not /user/. So caph.js should look like:
#!/usr/bin/env node
console.log("Hello World!");

Using subdependencies in npm script

Say I have a private npm package, #myprivate/repo which has the following contents in its package.json:
"scripts": {
"example": "db-migrate"
},
"bin": {
"foo": "bin/foo"
}
Where bin/foo is:
#!/bin/bash
npm run example
I now pull this into a parent repo with npm install:
package.json:
{
"dependencies": {
"#myprivate/repo": "*"
},
"scripts": {
"example": "unrelated command",
"useful": "foo"
}
}
Then running npm run useful results in the foo bin script getting called, which then attemps to call unrelated command. How do I scope the invocation to the dependency? How can I force a bin script to package its own npm dependency and rely on that? Is nested scripts in nested dependency package.json the best way, or is there a better more canonical solution?
I ended up being able to get the behaviour I want by changing the last line of bin/foo to:
npm explore #myprivate/repo npm run example
This does feel a little bit happy (I'm referencing the repo using npm explore from within itself), but it does get the job done. Would love to hear of a better solution

Run node module from powershell

Say that I have a folder with a node module installed inside. How can I, using powershell, run this module ? For example, I have a folder with webpack installed inside and I'd like to be able to do something like
node webpack
This does not work because it can't find the module. However, it works if I do:
node ".\node_module\webpack\bin\webpack.js"
However, I can't really use this because I'm working on a powershell script that allows the user to define a json file with actions. For example:
{
"type": "run-node",
"options": {
"module": "webpack",
"parameters": "--configFile=config/webpack.prod.js"
}
}
As the module to execute is dynamic, I don't know where it will be (except if all module are installed in ".\node_modules\module\bin\module.js" ?), so I can't launch it.
You can define a webpack script in your package.json:
"scripts": {
"webpack": "node \"./node_module/webpack/bin/webpack.js\""
}
Then you can use npm run webpack or yarn webpack to run it.
If you're trying to execute the command within the node.js script, use the __dirname variable.
__dirname (almost) always refers to the directory that contains the script.

local node js module not executing script

I am trying to create a simple node js plugin. Here is what I have done till now.
package.json
{
"name": "testcli",
"version": "0.0.1",
"description": "Test CLI Tool",
"main": "index.js",
"author": "BJ",
"license": "ISC",
"bin": {
"testx": "index.js"
}
}
Beside the package.json I have a file index.js that has a single line console.log('Hi!')
now when I install the package with npm install -g (from the same directory) and then run the command testx it gives me the following error
.../AppData/Roaming/npm/testx: line 1: /node_modules/testcli/index.js: No such file or directory
How can I solve this?
You need to add a shebang to tell the shell how to invoke this script.
Try adding #! /usr/bin/env node at the beginning of your script.
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.
For example, myapp could have this:
{ "bin" : { "myapp" : "./cli.js" } }
So, when you install myapp, it'll create a symlink from the cli.js script to /usr/local/bin/myapp.
If you have a single executable, and its name should be the name of the package, then you can just supply it as a string. For example:
{ "name": "my-program"
, "version": "1.2.5"
, "bin": "./path/to/program" }
would be the same as this:
{ "name": "my-program"
, "version": "1.2.5"
, "bin" : { "my-program" : "./path/to/program" } }
Please make sure that your file(s) referenced in bin starts with #!/usr/bin/env node, otherwise the scripts are started without the node executable!

OS independent access to variables in package.json

To access a variable in npm scripts you would do something like this in your package.json:
"scripts": {
"preinstall": "echo ${npm_package_name}"
}
The problem is that works only in Unix, not Windows, where you have to use %npm_package_name%.
Is there a way to do this OS independent? It will be good if npm could do such a variable expansion, before invoking the command.
To make it cross-platform, use cross-var:
"scripts": {
"preinstall": "cross-var echo ${npm_package_name}"
}
There's no known way to do this that's OS independent.
A good workaround is to execute the command within a node script:
First, change the preinstall command to execute a node script:
"scripts": {
"preinstall": "node nameEcho.js"
}
Then you define the command in the nameEcho.js file:
// require the package.json file
var pjson = require('./package.json');
// echo the package's name
console.log(pjson.name);

Resources