-
-
Save callumlocke/30990e247e52ab6ac1aa98e5f0e5bbf5 to your computer and use it in GitHub Desktop.
#### | |
# ZSH function to auto-switch to correct Node version | |
# https://gist.github.com/callumlocke/30990e247e52ab6ac1aa98e5f0e5bbf5 | |
# | |
# - Searches up your directory tree for the closest .nvmrc, just like `nvm use` does. | |
# | |
# - If you are already on the right Node version, IT DOES NOTHING, AND PRINTS NOTHING. | |
# | |
# - Works correctly if your .nvmrc file contains something relaxed/generic, | |
# like "4" or "v12.0" or "stable". | |
# | |
# - If an .nvmrc is found but you have no installed version that satisfies it, it | |
# prints a clear warning, so you can decide whether you want to run `nvm install`. | |
# | |
# - If no .nvmrc is found, it does `nvm use default`. | |
# | |
# Recommended: leave your default as something generic, | |
# e.g. do `nvm alias default stable` | |
#### | |
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 |
Hi! Thanks for this, this is very helpful!
I've added a few code that will show a prompt asking user to install the node version specified in .nvmrc
and switch to it automatically.
# 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 "No installed Node version found that satisfies .nvmrc."
echo " Do you want to install and use the specified Node version($REQUESTED_NODE_VERSION)? (Y/n)"
read -r INSTALL_NODE_VERSION
if [[ $INSTALL_NODE_VERSION =~ ^[Yy]$ ]]; then
# Install the requested Node version and switch to it
echo "Installing Node version $REQUESTED_NODE_VERSION..."
nvm install $REQUESTED_NODE_VERSION
echo "Node version $REQUESTED_NODE_VERSION installed."
echo "Switching to Node version $REQUESTED_NODE_VERSION..."
nvm use $REQUESTED_NODE_VERSION
echo "Node version switched to $REQUESTED_NODE_VERSION."
else
echo "Aborted installation. You can manually install the required Node version later."
fi
# Record that we already warned about this unsatisfiable .nvmrc file
export AUTOSWITCH_NODE_SUPPRESS_WARNING=$NVMRC_PATH
Awesome script! Thank you!
Is anyone using the
avn
+avn-nvm
packages? How does this compare? I think it supports.nvmrc
too.
FYI avn
is no longer maintained.
It's also worth mentioning to that add-zsh-hook chpwd auto-switch-node-version
should be added to your .zshrc
file. I was under the assumption that a “hook” was persistent between terminal sessions, and I couldn't work out why it stopped working after quitting my terminal. So make sure to run it every time your terminal window opens.
@callumlocke terrific job. Thank! 👏 👏 👏
I want to add some notes:
Adding the source causes lazy loading of NVM did not to work and can cause performance issues on terminal startup.
DON'T
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
Instead of that include the minimal code from https://github.dev/nvm-sh/nvm#zsh
to avoid the error message.
DO
nvm_echo() {
command printf %s\\n "$*" 2>/dev/null
}
# Traverse up in directory tree to find containing folder
nvm_find_up() {
local path_
path_="${PWD}"
while [ "${path_}" != "" ] && [ "${path_}" != '.' ] && [ ! -f "${path_}/${1-}" ]; do
path_=${path_%/*}
done
nvm_echo "${path_}"
}
nvm_find_nvmrc() {
local dir
dir="$(nvm_find_up '.nvmrc')"
if [ -e "${dir}/.nvmrc" ]; then
nvm_echo "${dir}/.nvmrc"
fi
}
I'm also forked it with a version who install the required version instead of showing a warning message:
auto-switch-node-version() {
local nvmrc_path=$(nvm_find_nvmrc)
local current_node_version=$(nvm version)
if [[ ! -z "$nvmrc_path" ]]; then
# .nvmrc file found!
# Read the file
local requested_node_version=$(cat $nvmrc_path)
# Find an installed Node version that satisfies the .nvmrc
local 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.
# 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.
if [[-z "$current_node_version"]]; then
# Install the requested version on the .nvmrc file
nvm install
else
# Install the requested version on the .nvmrc file with the current packages installed
nvm install --reinstall-packages-from=${current_node_version}
fi
fi
else
# No .nvmrc file found.
# Revert to default version, unless that's already the current version.
if [[ $current_node_version != $(nvm version default) ]]; then
nvm use default
fi
fi
}
This works super fine with me! Thanks for your code it's lit!