The Node Version Manager allows installing multiple NodeJS versions and switching between them.
By default, it does not automatically switch versions when entering a directory that holds a .nvmrc
file.
The project's
readme document
Show archive.org snapshot
offers a bash function which calls nvm use
after each cd
. In fact, it replaces cd
in your bash.
I did not want to do that, but instead use the $PROMPT_COMMAND
feature. So here is my take on it.
Note that it is much shorter, it probably does a few less smart things, but has been working great for me for a long while.
Also note that it compares .nvmrc
file paths instead of comparing nvm current
, so cd
ing around subdirectories of your project should work without any noticable performance impact.
Bash
Put the following at the end of your ~/.bashrc
(the first three lines might already be in there):
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
find-up() {
path=$(pwd)
while [[ "$path" != "" && ! -e "$path/$1" ]]; do
path=${path%/*}
done
echo "$path"
}
automatic-nvm-use() {
NVM_PATH=$(find-up .nvmrc | tr -d '[:space:]')
if [[ $NVM_PATH == $NVM_PATH_WAS ]]; then
return
fi
NVM_PATH_WAS=$NVM_PATH
if [[ -f "$NVM_PATH/.nvmrc" ]]; then
nvm use $(<"$NVM_PATH/.nvmrc")
else
nvm use default
fi
}
if [[ "$PROMPT_COMMAND" ]]; then
export PROMPT_COMMAND="$PROMPT_COMMAND;automatic-nvm-use"
else
export PROMPT_COMMAND=automatic-nvm-use
fi
Then re-open your terminals, or reinitialize them via source ~/.bashrc
.
Note
If your
~/.bashrc
contains other code that changes$PROMPT_COMMAND
(like making your terminal's title reflect the current directory), make sure it does not simply set a new$PROMPT_COMMAND
, but prepends or appends itself. Alternatively, put the above snippet after it.
ZSH
For zsh this script Show archive.org snapshot from the following stackoverflow post Show archive.org snapshot seems to work the most stable and covers additional features such as
- guarantees you are always on the right version by searching up the directory tree to find the closest .nvmrc (just like nvm use);
- can handle any valid .nvmrc format;
- clearly warns you if no installed version satisfies the .nvmrc,
- assumes you want default if there is no .nvmrc anywhere up the tree;
- is completely silent and fast if you are already on the correct Node version.
auto-switch-node-version() {
NVMRC_PATH=$(nvm_find_nvmrc)
CURRENT_NODE_VERSION=$(nvm version)
if [[ ! -z "$NVMRC_PATH" ]]; then
# .nvmrc file found!
# Read the file
REQUESTED_NODE_VERSION=$(cat $NVMRC_PATH)
# Find an installed Node version that satisfies the .nvmrc
MATCHED_NODE_VERSION=$(nvm_match_version $REQUESTED_NODE_VERSION)
if [[ ! -z "$MATCHED_NODE_VERSION" && $MATCHED_NODE_VERSION != "N/A" ]]; then
# A suitable version is already installed.
# Clear any warning suppression
unset AUTOSWITCH_NODE_SUPPRESS_WARNING
# Switch to the matched version ONLY if necessary
if [[ $CURRENT_NODE_VERSION != $MATCHED_NODE_VERSION ]]; then
nvm use $REQUESTED_NODE_VERSION
fi
else
# No installed Node version satisfies the .nvmrc.
# Quit silently if we already just warned about this exact .nvmrc file, so you
# only get spammed once while navigating around within a single project.
if [[ $AUTOSWITCH_NODE_SUPPRESS_WARNING == $NVMRC_PATH ]]; then
return
fi
# Convert the .nvmrc path to a relative one (if possible) for readability
RELATIVE_NVMRC_PATH="$(realpath --relative-to=$(pwd) $NVMRC_PATH 2> /dev/null || echo $NVMRC_PATH)"
# Print a clear warning message
echo ""
echo "WARNING"
echo " Found file: $RELATIVE_NVMRC_PATH"
echo " specifying: $REQUESTED_NODE_VERSION"
echo " ...but no installed Node version satisfies this."
echo " "
echo " Current node version: $CURRENT_NODE_VERSION"
echo " "
echo " You might want to run \"nvm install\""
# Record that we already warned about this unsatisfiable .nvmrc file
export AUTOSWITCH_NODE_SUPPRESS_WARNING=$NVMRC_PATH
fi
else
# No .nvmrc file found.
# Clear any warning suppression
unset AUTOSWITCH_NODE_SUPPRESS_WARNING
# Revert to default version, unless that's already the current version.
if [[ $CURRENT_NODE_VERSION != $(nvm version default) ]]; then
nvm use default
fi
fi
}
# Run the above function in ZSH whenever you change directory
autoload -U add-zsh-hook
add-zsh-hook chpwd auto-switch-node-version
auto-switch-node-version