How can I pass a string as an argument to an NPM script that is then passed to a CLI command? - node.js

I'm setting up a new react project, and I'd like to use the generate-react-cli package so that I can easily generate components instead of manually having to create files.
However the command to run the tool is lengthly, so I'd like to cut that down using an NPM script. The command is npx generate-react-cli component Box
So preferably I'd like to be able to do something like npm run grc Box and then have "Box" be passed as an argument to an NPM script that looks like
"scripts": {
"grc-c": "npm generate-react-cli component $1"
},
I've tried this using -- parameters but it didn't work as it parses it incorrectly.

You can revert the script to:
"scripts": {
"grc-c": "npm generate-react-cli component"
},
And use:
npm run grc-c -- Box

Related

How to run node.js cli with experimental-specifier-resolution=node?

Our team has built a small CLI used for maintenance. The package.json specifies a path for with the bin property, and everything works great; "bin": { "eddy": "./dist/src/cli/entry.js"}
Autocompletion is achived by using yargs#17.0.1. However we recently converted the project to use es6 modules, because of a migration to Sveltekit, i.e. the package.json now contains type: module. Because of this, the CLI now only works if we run with:
what works
node --experimental-specifier-resolution=node ./dist/src/cli/entry.js help
However, if we run this without the flag, we get an error "module not found":
Error [ERR_MODULE_NOT_FOUND]: Cannot find module...
So the question is
Can we somehow "always" add the experimental-specifier-resolution=node to the CLI - so we can continue to use the shorthand eddy, and utilize auto completion?
There are two probable solutions here.
Solution 1
Your entry.js file should start with a shebang like #!/usr/bin/env node. You cannot specify the flag directly here, however, if you could provide the absolute path to node directly in the shebang, you can specify the flag.
Assuming you have node installed in /usr/bin/node, you can write the shebang in entry.js like:
#!/usr/bin/node --experimental-specifier-resolution=node
(Use which node to find the absolute path)
However, this is not a very portable solution. You cannot always assume everyone has node installed in the same path. Also some may use nvm to manage versions and can have multiple version in different path. This is the reason why we use /usr/bin/env to find the required node installation in the first place. This leads to the second solution.
Solution 2
You can create a shell script that would intern call the cli entry point with the required flags. This shell script can be specified in the package.json bin section.
The shell script (entry.sh) should look like:
#!/usr/bin/env bash
/usr/bin/env node --experimental-specifier-resolution=node ./entry.js "$#"
Then, in your package.json, replace bin with:
"bin": { "eddy": "./dist/src/cli/entry.sh"}
So when you run eddy, it will run the entry.js using node with the required flag. The "$#" in the command will be replaced by any arguments that you pass to eddy.
So eddy help will translate to /usr/bin/env node --experimental-specifier-resolution=node ./entry.js help
Just add a script to your package.json:Assuming index.js is your entry point and package.json is in the same directory
{
"scripts": {
"start": "node --experimental-specifier-resolution=node index.js"
}
}
Then you can just run on your console:
npm start

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

'standard' is not recognized as an internal or external command

I want to integrate some kind of code linting for node.js in webstorm so I installed standard to my node.js project using:
npm instal standard --save-dev
It was installed and listed in the "devDependencies" section of package.json but when I run the command:
standard
in the console I get
'standard' is not recognized as an internal or external command
if you want to use it locally you have to include it in you scripts first in package.json
"scripts": {
"standard": "standard",
"standard::fix": "standard --fix"
}
and use npm run standard to run it. or if you are using yarn type yarn standard
The scripts are in node_modules\.bin.
So, either:
Add this to PATH before running standard, e.g.:
set PATH=%PATH%;node_modules\.bin
Run it in using node_modules\.bin\standard
Use #tarek's approach using package.json: https://stackoverflow.com/a/49026837/122441
"scripts": {
"test": "standard middlewares/validations.js"
}
Add above lines in package.json.
Here middlewares/validations.js is the path of the file to check.
Run -> npm test
If this file have any error you will get.

Inject argument into npm script command

I have an npm script that looks like:
"scripts": {
"example": "webpack-dev-server --content-base examples/embeddable/"
},
I'd like to form the --content-base argument dynamically based on whatever's passed when calling the npm script, like:
npm run example -- embeddable
I know the -- syntax works for making args available to process.argv, but I'm not calling a Node script here so I'm not sure how to access them when forming the command. Does anyone else know of a good, cross-platform way to do this? (Must work on Windows 7, i.e. without bash capabilities.)
This should work ($1 is replaced by whatever you add as first parameter):
"scripts": {
"example": "webpack-dev-server --content-base examples/${1}/"
},
Run it like this:
npm run example -- embeddable

npm postinstall fails with multiple commands

Inside my composer.json, there's a postinstall hook setup like the following:
"scripts" : {
"dist" : "node dist; node_modules/.bin/doccoh src/package.js",
"postinstall" : "node_modules/.bin/grunt setup || true; node_modules/.bin/bower install",
"start" : "node server.js"
}
Whenever I run it (on Win from Git/Gnu Bash CLI), I end with
command not found. either the command was written wrong or couldn't be found
Rough translation from German CLI error.
I tried splitting it into multiple ;/semicolon separated parts and first cd into that directory, but it simply ends up with the same error message. Replacing the whole postinstall command set with a simple ls does work. So I guess the problem might be the semicolon separation or a wrong usage of commands. But overall I got no idea what's wrong.
Note: I got grunt-cli version 0.1.9 and grunt version 0.4.1 installed globally.
I'm a bit late to answer, but if you're on Windows, multiple commands on a single line are executed with the use of &&
postinstall: "some command && some other -c"
I ran into this looking for something and thought this may help other people. I have found it easier to move to postinstall.js files as things get a little complicated. This makes it easier to deal with moving forward.

Resources