npm run script deletes flags - npm

In my package.json in scripts i have this
"typeorm": "ts-node ./node_modules/typeorm/cli.js"
i want to be able to extend this script from cli usage eg.
npm run typeorm migration:create -n Example
but when i do run it like that in terminal this gets executed:
ts-node ./node_modules/typeorm/cli.js "migrations:create" "Example"
note that the flag -n is being deleted by npm
Do you know how would i run scripts like this and keep flags and everything thank you.

Okay i have found an answer ... just add -- after npm run typeorm
example:
npm run typeorm -- migration:create -n Example
everyting after -- will be added directly to script according to docs

Related

How to execute nested "npm run commands" inside an npm#^7.0.0 monorepo set up within the context of the current workspace?

I have a monorepo with several workspaces within it. It has been very common for me to use chained npm scripts for simple tasks instead of using a task runner. So for example, the following configuration (pseudo code) is very common for me and usefull as well, specially for pre and post build scripts
"scripts": {
"prebuild:task1":"task1 --task1-arguments",
"prebuild:task2":"task2 --task2-arguments",
"prebuild": "npm run prebuild:task1 && npm run prebuild:task2",
"build":"build-script --build-arguments",
}
So the above is the package.json for the child worskpace itself and then in the master package.json I have the call to the script that triggers the build for that workspace.
build:packageA: "npm run build -w packageA"
All seems working well but the chained "npm run script" inside the workspace is actually execute in the context of the master monorepo and not inside that particular workspace.
So, in summary, the first call is to run the build script in the workscape and then triggers the prebuild script of that workspace BUT as that script execute chained npm run scripts those are run in the context of the master repo which happens that they don't exist in there. So the callstack might be ...
(master) build:packageA
(packageA) prebuild
(master) npm run prebuild:task1 >>>> EXIT ERROR
The only way I found, up to now, to bypass this issue was to make my child workspace a monorepo itself holding zero woskpaces. Essentially I have a "workspaces" key in its package.json pointing to the root directory. This enables me to use the -w flag in the scripts section so to refer all scripts to itself. So my current workaround looks like this ...
"workspaces": ["."],
"scripts": {
"prebuild:task1":"task1 --task1-arguments",
"prebuild:task2":"task2 --task2-arguments",
"prebuild": "npm run prebuild:task1 -w packageA && npm run prebuild:task2 -w packageA",
"build":"build-script --build-arguments -w packageA"
}
Isn't there already a better way to solve this?
Thanks in advance to everyone!
Following this post https://stackoverflow.com/a/67060676 I found out that npm changed the way it calls nested scripts in workspaces.
I ran into similar issues like you while running npm#7.5, but the feature was introduced in npm#7.7. Updating node to v17 and npm to 8.3 resulted in everything is running as intended.
In my case I wanted to execute nested npm run build commands in workspaces.

Run a script (like postinstall) after npm installing a single package?

I'm starting to play around with Snowpack. It takes a different approach from Webpack by bundling individual packages right after they're installed.
The "issue" is, when I install a package I have to first run npm install --save my-package and then I have to manually pack it with npx snowpack. The Snowpack docs mention that I can include a prepare script that would snowpack everything after running npm install but that doesn't apply to individual packages, just on a generic npm install of all dependencies in my package.json. As far as I can tell, this is the case for all npm hooks mentioned in the npm docs.
Is there any way I can automatically run a script whenever I install an individual package? The only way I can think of would be to overwrite the install script and add something to it. Are there any examples of this on GitHub or elsewhere?
Update: For clarification, I'd like to run npx snowpack every time I install a new package with --save but preferably not with --save-dev or without --save. This will never be different for any package. This will be specific to a certain repo/project, not global on my system.
It is not sufficient to run snowpack after simply running npm install as you would get by hooking into postinstall or release. Additionally, I want to make sure developers working on my project can use npm install --save newdep as they normally would and then snowpack will run. I do not want to require devs to use a custom named script.
Short answer: Unfortunately, npm does not provide any built-in feature(s) to meet your requirement.
Lifecycle hooks/scripts such as postinstall are invoked only when running the generic npm install command, and not when someone runs npm install --save <pkg_name> during the projects development phase.
Workaround: Consider customizing the logic of the npm install --save compound command by essentially overriding the npm command at the shell level.
The following solution, albeit a Bash one, describes how this custom logic can be actualized for a specific project(s). However, this solution is dependent on the following conditions:
Developers working on your project must have their the shell set to Bash when running the npm install --save compound command.
Developers working on your project will need to customize their Bash startup files, namely ~/.bashrc and possibly ~/.bash_profile.
The project directory, i.e. the project directory for which you want the custom logic to be effective, must contain a custom .bashrc file.
Bash Solution:
The following three steps are necessary to configure your project, and operating system(s), so that when a developer runs npm install --save <pkg_name> (or variations of it) the npx snowpack command is subsequently invoked.
Note: Points two and three (below) are the tasks developers need to carry out (once) to customize their Bash startup files.
The project specific .bashrc file:
Firstly create the following "project specific" .bashrc file in the root of your project directory, i.e. save it at the same level as where your projects package.json file resides:
/some/path/to/my-project/.bashrc
npm() {
local name_badge="\x1b[37;40mpostinstall\x1b[0m"
array_includes() {
local word=$1
shift
for el in "$#"; do [[ "$el" == "$word" ]] && return 0; done
}
log_warn_message() {
local cmd_name=$1 warn_badge warn_mssg
warn_badge="\x1b[30;43mWARN!\x1b[0m"
warn_mssg="${cmd_name} command not found. Cannot run npx snowpack."
echo -e "\n${name_badge} ${warn_badge} ${warn_mssg}" >&2
}
log_run_message() {
echo -e "\n${name_badge} Running pseudo postinstall hook."
}
if [[ $* == "install "* || $* == "i "* ]] && array_includes --save "$#"; then
# 1. Run the given `npm install --save ...` command.
command npm "$#"
# 2. Check whether the `npx` command exists globally.
command -v npx >/dev/null 2>&1 || {
log_warn_message npx
return 1
}
log_run_message
# 3. Run the pseudo "postinstall" command.
command npx snowpack
else
# Run all other `npm` commands as per normal.
command npm "$#"
fi
}
Note: For a better understanding of what this file does refer to the "Explanation" section below.
The ~/.bashrc file:
To make the custom logic, i.e. the npm function in the aforementioned .bashrc file, effective, it's necessary to configure Bash to read the aforementioned "project specific" .bashrc file. To configure this, add the following line of code to ~/.bashrc:
PROMPT_COMMAND='if [[ "$bashrc" != "$PWD" && "$PWD" != "$HOME" && -e .bashrc ]]; then bashrc="$PWD"; . .bashrc; fi'
Note: For a better understanding of what this line of code does refer to the "Explanation" section below.
The ~/.bash_profile file:
Typically your ~/.bash_profile contains the following line of code to load the ~/.bashrc file (or some variation of it):
if [ -f ~/.bashrc ]; then . ~/.bashrc; fi
If this is not present, then it must be added to ~/.bash_profile.
Additional info.
Setup/Configuration helpers:
Consider your developers utilizing the following two commands to aid configuration of their Bash startup files, as per the aforementioned steps two and three.
For step two, run the following command:
echo $'\n'"PROMPT_COMMAND='if [[ \"\$bashrc\" != \"\$PWD\" && \"\$PWD\" != \"\$HOME\" && -e .bashrc ]]; then bashrc=\"\$PWD\"; . .bashrc; fi'" >> ~/.bashrc
This will add the PROMPT_COMMAND=... line of code to the existing ~/.bashrc file, or create a new one if it doesn't already exist:
For step three, run the following command to append the line of code necessary in the ~/.bash_profile for loading the ~/.bashrc file:
echo $'\n'"if [ -f ~/.bashrc ]; then . ~/.bashrc; fi" >> ~/.bash_profile
Is my shell configured to Bash?
To check whether the shell is configured to Bash you can create a new session, i.e. create a new Terminal window and run:
echo $0
If it prints -bash then it's using Bash.
How do I configured my shell to Bash?
If echo $0 doesn't print -bash then you'll need to change the shell. To change it to Bash run:
chsh -s /bin/bash
Note: You'll need to create a new session for this change to become effective.
Explanation
The project specific .bashrc file:
This .bashrc file contains a shell function named npm. The body of this function contains the logic necessary to override the default npm install|i --save command.
The conditions specified in the if statement, i.e, the part that reads;
if [[ $* == "install "* || $* == "i "* ]] && array_includes --save "$#"; then
...
fi
essentially reads the $* special parameter to check whether the argument(s) passed to the npm function begin with either; install , or it's shorthand equivalent i , and whether the --save option/argument has been passed too.
To check for the existence of the --save argument we pass the $# special parameter to the array_includes function. We handle this argument differently because the position of the --save option may differ in the compound command. For instance, a user may install a package by running this;
# Example showing `--save` option at the end
npm install <pkg_name> --save
or this (or some other variation):
# Example showing `--save` option in the middle
npm i --save <pkg_name>
When the conditions specified in the if statement are met, i.e. they're true, we perform the following tasks in its body:
Run the given npm install --save ... command as-is via the line that reads:
command npm "$#"
Check whether the npx command exists globally via the part that reads:
command -v npx >/dev/null 2>&1 || {
log_warn_message npx
return 1
}
If the npx command is not available (globally) we warn the user that the npx snowpack command cannot be run, and return from the function early with an exit status of 1.
Note: My logic in this check assumes that you'll be installing npx globally. However if you're installing npm locally within your project then you'll need to change this logic. Perhaps by checking whether ./node_modules/.bin/npx exists instead. Or, you may be confident that npx command will always exists, therefore conclude that this check is unnecessary.
If the npx command exists globally we then run the pseudo "postinstall" command, i.e.
command npx snowpack
When the conditions specified in the if statement are NOT met, i.e. they're false, the user is essentially running any other npm command that is not npm install --save <pkg_name>. Therefore in the else branch we run the command as-is:
command npm "$#"
The ~/.bashrc file:
In section 5.2 Bash Variables of the "Bash Reference Manual" the PROMPT_COMMAND variable is described as follows:
PROMPT_COMMAND
If set, the value is interpreted as a command to execute before the printing of each primary prompt ($PS1).
So, this line of code (here it is again):
PROMPT_COMMAND='if [[ "$bashrc" != "$PWD" && "$PWD" != "$HOME" && -e .bashrc ]]; then bashrc="$PWD"; . .bashrc; fi'
loads the "project specific" .bashrc (if one exists), which in turn overrides the npm command with the npm function. This is what essentially provides a mechanism for overriding the npm install --save compound command for a specific project(s).
See this answer by #Cyrus for further explanation.
With newer versions of Snowpack (>=2) you can run snowpack dev and it will watch your npm_modules folder for new modules to build.
I think the best bet would be to create a new script that performs the desired action. Something along the following lines in your package.json:
{
"scripts": {
"snowpack-install" : "npm install --save && npx snowpack"
}
}
Correction
You can actually use the postinstall option in package.json. The postinstall will run "AFTER the package is installed". This would look something like the following:
{
"scripts": {
"postinstall" : "npx snowpack"
}
}

What does npm run bundle do?

I'm trying to understand and follows https://github.com/DMPRoadmap/roadmap/wiki/Installation
But I don't understand something they use.
What does these do?
1) npm run bundle
I know it equals to npm run-script bundle as according to npm doc about run script but I don't really understand where the bundle come from; in other words, I don't understand what npm doc about run script mean by
an arbitrary command from a package's script object
2) npm run bundle -- -p
Since I don't know where the bundle come from, I don't know how to work out the meaning of -- -p option. I want to find its documentation and see the details.
I'm not sure if npm doc about bundle is related, but it seems to be replaced by install as documented in npm doc about install.
And why is this option got so many - characters (3 in this case) before p? I normally see 2 - for long option name and 1 - for abbreviated option name
Any time you see npm run [x] anywhere it means that it's executing a command located in the scripts section of the package.json file. Therefore npm run bundle runs the bundle command located here: https://github.com/DMPRoadmap/roadmap/blob/master/lib/assets/package.json#L8 which in this case looks like all it's doing is running webpack
"scripts": {
"test": "./node_modules/.bin/karma start",
"bundle": "./node_modules/.bin/webpack",
"lint": "./node_modules/.bin/eslint --ext .js --cache ./javascripts/ || true"
}

What does -s mean in npm command?

I saw the following command that includes -s option. What does it(-s) mean? Because I didn't see the option in package.json.
$ npm run dev -s
The flag -s stands for "silent" and is applied to npm, not to the command in the dev script.
The -s flag prevents npm from screaming at you when the command exits with a non-zero status, i.e. when the command fails. It also won't create an npm_debug.log file.
To test out the difference yourself you can do the following in a new directory.
npm init -y
npm run test
npm run test -s
Note 1: I prefer to write npm run -s dev to limit possible confusion.
Note 2: To pass the -s flag to the dev script, you would run npm run dev -- -s.

What is the difference between yarn run and npm start?

Is yarn run intended to be the equivalent of npm start?
It seems yarn run start is the equivalent of npm start, which runs the script inside the start field of the script field in package.json
Few things to understand:
npm: run command is mandatory to execute user defined scripts.
yarn: run command is not mandatory to execute user defined scripts.
start command is not a user defined script name, so you may not need to specify run command to execute it.
So, all the below commands work similar!
npm start
npm run start
yarn start
yarn run start
If you have a user defined script named 'app':
npm app (Does not work!)
npm run app (Works!)
yarn app (Works!)
yarn run app (Works!)
Note: By default start runs node server.js in case not explicitly defined.
npm start is a shortcut for npm run start
Now in terms of running scripts from package.json, all these are equivalent:
npm run start
npm start
yarn run start
yarn start
npm run myscript
npm myscript this is an error
yarn run myscript
yarn myscript
This is because run is not mandatory command for yarn, but it is for npm.
Bonus
npr start - OK
npr myscript - OK
Put this file somewhere in PATH, eg. %localappdata%\Programs\Git\cmd
npr.cmd
npm run %*
yarn run is similar to npm run, they can be used to run the scripts in package.json.
For npm, you can leave out run when run the npm lifecycle scripts (test, start, restart, and stop), but these scripts maybe have extra effect. For example, npm start will run node server.js if the "scripts" object does not define a "start" property in package.json. see the doc npm run. You can't run script with other name leaving out run.
For yarn, you can leave out run for all the scripts in package.json, but if your script name is same as yarn built-in cli commands, the built-in cli commands will have preference over your scripts. doc yarn run.
So the best way to run scripts in package.json: never leave out run.