how to add a custom NPM postinstall script? - node.js

whenever I run npm install it runs npm run postinstall. how can I add a custom post install script? so that after running npm install it runs npm run postinstall2?

You call multiple scripts from postinstall by chaining them with &&:
{
"scripts": {
"script1": "",
"script2": "",
"postinstall": "script1 && script2"
}
}
This should work on both Windows and Unix (Linux, macOS) terminals.

Related

How to run few npm scripts in one-line shell command?

I have three scripts in package.json:
Watch server TypeScript
Nodemon
Webpack
"scripts": {
"watch-server": "tsc --watch --project ./server/tsconfig.json",
"watch-node": "nodemon --watch ./server/build/ --watch ./server/templates -e js,json,pug",
"watch-client": "webpack --config ./webpack/webpack.dev.conf.js --watch"
}
Everytime I start my computer and open VS Code I need to open three separate PowerShell terminals and type in those commands one-by-one. Is there any way to launch these three separate terminals with their own commands in one shell command? Maybe via tasks.json?
On linux or any bash terminal, you can use && to combine multiple commands, i
You can do as
npm run watch-server && npm run watch-node && npm run watch-client
A quick google search for powershell suggested using semicolon
so on powershell you can do something like below if using && does not work
npm run watch-server;npm run watch-node ; npm run watch-client
Also keep in mind, you can additionally add fourth command in your npm scripts in package.json where you can use one of these combined commands which works for you, like
start-all: npm run watch-server && npm run watch-node && npm run watch-client
and then run
npm run start-all

execute several "npm scripts" in order

I would like to command "electron-packer ." (it takes some time) and then "asar pack app app.asar"
Is it possible to do this?
Or should I simply wait for the first one and command the second?
You can queue commands like this.
npm run pack1 && npm run pack2
Or you can add another line that does the above and just run that alone.
"scripts": {
"pack": "npm run pack1 && npm run pack2"
}
Add this inside your "scripts" and you can just run npm run pack to run both of those commands.

Pass npm script command line arguments to a specific script inside it

I have a scenario where I have to run three npm script to achieve some result in my application. I combined them in one npm script. This is my package.json:
"scripts": {
"setup": "npm install && npm run some-script && npm install",
"some-script": "gulp some-other-script"
}
what I would like to do is to pass arguments to setup script from command line which will be passed further to the some-script script.
If I run npm run script -- --abc=123 the arguments are added at the end of the script but I would like to pass it to specific script (in this case to npm run some-script). I also tried to rewrite script definition like this:
"setup": "npm install && npm run some-script -- --sample=sample&& npm install" but with no luck.
I'm aware of shell functions (described here: Sending command line arguments to npm script and here https://github.com/npm/npm/issues/9627) but I need a solution which will work cross-platform.
Is there a way to do that?
Ok I found a work around.
1st goal was to be able to use some script with arguments, and cascade this to the calls of other scripts :
npm run main -- --arg1
"main": "npm run script1 && npm run script2"
Problem with this approach is that the cascading would only be done by adding the arg passed to npm run main at the END of the line "npm run script1 && npm run script2". I could find no way to pass it to the 1st element : npm run script1
Here is the work around I found :
1st you need to add in package.json:
"config": {
"arg1": "ARG_VALUE"
},
Then in your script you can add it to the call like this :
"main": "npm run script_no_arg1 && npm run scrip1 -- --%npm_package_config_arg1% && npm run script2 -- --%npm_package_config_component% && npm run script_no_arg2"
Finally, You don't need to call it with any arg : npm run main
But you need to modify ARG_VALUE before launc the script :)
Last thing : in my case I was calling gulp tasks :
"cleardown": "rimraf build lib",
"inline-build-templates": "gulp inline-build-templates",
"step1": "npm run cleardown && npm run inline-build-templates -- --%npm_package_config_arg1%",
It works you can get the argument into the gulp task that way :
gulp.task('inline-build-templates', function() {
let component = process.argv[3];
component = component.split('--')[1];
console.log('RUNNING GULP TASK : inline-build-templates for component ' + component);
// whatever task gulp
});
Hope it helps.

Execute script after package installation

Now, I there is postinstall to run a script after
npm install
However, I am looking for a way to run a script after installing a single package
npm install jquery --save
Is this possible? If so, does this work on Windows and is there a way to get the name of the installed package (jquery in the given example)?
I'm don't see this on the package.json features.
It is therefore possible to do in the prestart for instance but jquery won't be in the devDependencies that way:
{
...
"devDependencies": {
"bower": "1.3.x",
"uglifyjs": "2.4.10",
... your other dependencies
},
"scripts": {
"prestart": "npm install jquery##.#.# ; <yourcommand> ; npm install",
...
}
}

How to detect when `prepublish` script is executed as a result of running `npm install`

https://docs.npmjs.com/misc/scripts
prepublish: Run BEFORE the package is published. (Also run on local npm install without any arguments.)
I want my script to execute only in case of user executing npm publish. However, NPM will execute "prepublish" script if user runs "npm install".
The only way I have figured out is using NPM internal ENV variables:
// NPM will run prepublish script after `npm install` (https://docs.npmjs.com/misc/scripts)
// This ensures that when script is executed using `npm *` it is run only when the command is `npm publish`.
if (process.env.npm_config_argv) {
let npmConfigArgv;
npmConfigArgv = JSON.parse(process.env.npm_config_argv);
if (npmConfigArgv.original[0] !== 'publish') {
console.log('`bundle-dependencies prepublish` will not execute. It appears that `prepublish` script has been run by `npm install`.');
return;
}
}
It appears that NPM stores the original command in process.env.npm_config_argv variable.
In case you are wondering, each NPM script is being run in different process. Therefore, something like setting a custom ENV variable in preinstall script does not work.
Another solution that's also worked for me (again from this thread) is using a prepublish.sh script like the following:
get_json_val() {
python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))";
}
get_npm_command() {
local temp=$(echo $npm_config_argv | get_json_val "['original'][0]")
echo "$temp" | tr -dc "[:alnum:]"
}
if [ $(get_npm_command) != "publish" ]; then
echo "Skipping prepublish script"
exit 0
fi
# else
echo "prepublish called"
# prepublish logic follows:
# ...
So if your package.json file is:
{
"name": "foo",
"version": "0.0.1",
"description": "",
"main": "lib/foo.js",
"scripts": {
"prepublish": "./prepublish.sh"
},
"dependencies": {
"lodash": "^4.10.0"
}
}
… then running npm install will only install the dependencies and the prepublish target will only be called when user types npm run publish.
Yet another way is to use the in-publish package (again mentioned in this thread). Place it in your development dependencies and then in your package.json have something like:
"prepublish": "(in-publish && npm run clean && flow check && npm run test && npm run build) || not-in-publish"
As of npm#4.0.0, the prepublish script is now deprecated. To run a script on both npm publish, and npm install without arguments (the bahaviour of prepublish), you should use prepare instead.
To run a script only on npm publish, you should use prepublishOnly.

Resources