I have a script in my package.json
:
{
"scripts": {
"start": "source run-nvm.sh && ..."
}
}
But running source run-nvm.sh && ...
is different to yarn start
(or npm run start
).
Why? It creates a subshell. So I can't change environment of the original shell, I can't export
constants for it or manipulate the state of nvm
(I can't change node version for the parent shell)
Can I execute yarn/npm script by not creating a subshell? (and use the current shell)
OR
How to source shell script with npm scripts?
Eventually, you may try to change the discourse by asking: "why don't you just source run-nvm.sh && yarn start
" but I don't want to just add some custom scripts and complexity, I want it to be automatically executed on yarn start
/ npm start
(to change node version automatically)
It works currently (the script changes the version of node and runs the app) but since it's a subshell it does not save the state of nvm. So on every yarn start
it's using default version initially, then changes the version, then starts the app, so it adds ~3-4 seconds for the yarn start
command for the version change. While it shouldn't set the version every time, but should set it just once, for the first time.
I faced this problem today and I found a simple solution that works for me.
Create a env file with the vars
# cat > .env << EOF
PORT=8080
DB_HOST=my-db.host
DB_PORT=3306
DB_USER=mysql
DB_PASS=123456
EOF
Create a new entry on the package.json
file
{
[...]
"start": "export $(cat .env | egrep -v '#|^$' | xargs) && node production-server/server.js",
[...]
}
Start the app as usual
# npm run start
> [email protected] start /usr/local/myapp
> export $(cat .env | egrep -v '#|^$' | xargs) &&
node production-server/server.js
> Ready on http://localhost:8080
Thats all.
If you want to know what export $(cat .env | egrep -v '#|^$' | xargs)
does, keep reading.
export $(cat .env | egrep -v '#|^$' | xargs)
| | | |
| | | transform the output in "PORT=8080 DB_HOST=my-db.host DB_PORT=3306 DB_USER=mysql DB_PASS=123456"
| | |
| | filter lines starting with comment or blank line
| |
| cat the .env file
|
save the env on subshell before start the node
Spotted your comment about using a vscode plugin If all your looking for is to change your nvm version for all terminals when the version differes on one of your projects then check out my overkill answer.
I will probably put all of the logic in a bash script and just share the link. 👍
Usually version of node is stored in the package.json and causing an incorrect version of node or npm to cause a failure.
// package.json
"engines": {
"node": ">=10.0.0"
},
"scripts": {
Usually version logic is in bashrc sourced by the shell in the $HOME/.bashrc file. when new window windows are created they re-trigger nvm use.
Two possibilities:
both use script: script-to-replace-nvm-version.sh# Which replaces in bashrc the "nvm use " line with "nvm use $correctProjectVersion"
Use start script in package json to run script-to-replace-nvm-version
Use PROMPT_COMMAND to run script-to-replace-nvm-version:
a check is used here to make sure we are on an npm project.
be careful with PROMPT_COMMAND as it will run every time before the ps1 renders.
PROMPT_COMMAND="[ -f ./package.json ] && $HOME/.scriptsourcedbybashrc.sh"
Script Summary: Nvm is usually sourced with the particular version in $HOME/.bashrc. Therefore we could the npm package rewrite the line containing nvm use ... and update the version. We could even prompt the user with do you wish to update?
check node version from package.json
projectVersion=$(cat ./package.json | grep 'node":' | tr -dc '0-9.')
echo $projectVersion
check node version from $HOME/.bashrc
nodeVersion=$(cat $HOME/.bashrc | grep 'nvm use' | tr -dc '0-9.')
echo $nodeVersion
check if node and package.json versions differ
# bash script, to be sourced by npm run start;
# WIP, needs a few more error checks
# such as, nvm used in more than one place in your bashrc.
if
versions_differ_tell_and_prompt
fi
versions_differ_tell_and_prompt() {
echo "nvm versions differ: ";
found in project: $projectVersion;
found in '$HOME/.bashrc': $nodeVersion;
echo ;
echo "ignore with any keypress or [uU] to update";
old_stty_cfg=$(stty -g);
stty raw -echo ; answer=$(head -c 1) ; stty $old_stty_cfg;
}
if echo "$answer" | grep -iq "^u" ;then
update_file 'nvm use' "nvm use $projectVersion" && source $HOME.bashrc;
else
echo "No changes made";
fi
update_file() {
searchLine=$1
replacementLine=$2
lineNumber=$(cat $HOME/.bashrc | grep -n $searchLine | cut -f1 -d:)
cp "$HOME/.bashrc" "$HOME/.bashrc.backup"
sed -i "$lineNumbers/.*/$replacementLine/" "$HOME/.bashrc"
source "$HOME/.bashrc"
}
unset searchLine
unset replacementLine
unset answer
unset old_stty_cfg
unset nodeVersion
unset projectVersion
Some other helpful links: https://github.com/md-command-line/ERRORSCREAM/issues/2
took most of the logic from here: https://github.com/MichaelDimmitt/git_check_computer/blob/master/git_check_computer.sh
correct the yarn start command to run the correct yarn or npm based on the lockfile found. https://github.com/MichaelDimmitt/know-your-package-manager
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With