How to write a .nvmrc file which automatically change node version
As @Aditya-M-P has already mentioned you can run the following command inside your projects root directory to generate the .nvmrc
to set a desired NodeJS version for you project to work properly:
node -v > .nvmrc
It will generate something like this inside your .nvmrc
file:
v10.16.2
Also using 10.16.2
without the v
letter will work just fine.
However, in the official documentation in the .nvmrc section it never mentions that once you get this file created, the specified node version will be loaded automatically.
So that's not enough, you need to run the command below so that nvm
can look for the .nvmrc
file to load the specified version:
nvm use
Here it is a gif for demoing purpose:
To autoload the specified node version:
You need to add something else to your shell configuration depending on what you use bash
or zsh
To get the exact configuration for each of them, please follow the instructions in the corresponding shell config section.
In my case I'm using zsh
so I do need to add this at the end of my .zshrc
file and here is the image that confirms it works like a charm:
# place this after nvm initialization!
autoload -U add-zsh-hook
load-nvmrc() {
local node_version="$(nvm version)"
local nvmrc_path="$(nvm_find_nvmrc)"
if [ -n "$nvmrc_path" ]; then
local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")
if [ "$nvmrc_node_version" = "N/A" ]; then
nvm install
elif [ "$nvmrc_node_version" != "$node_version" ]; then
nvm use
fi
elif [ "$node_version" != "$(nvm version default)" ]; then
echo "Reverting to nvm default version"
nvm use default
fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc
I hope it could be useful for anyone else facing the same question! 😎
Check the README from nvm's repo on GitHub. Solutions have been given there.
Shell Integraton
For bash, put the following at the end of your $HOME/.bashrc
, the shell will change the node version according to the .nvmrc
file under the dir.
find-up () {
path=$(pwd)
while [[ "$path" != "" && ! -e "$path/$1" ]]; do
path=${path%/*}
done
echo "$path"
}
cdnvm(){
cd "$@";
nvm_path=$(find-up .nvmrc | tr -d '[:space:]')
# If there are no .nvmrc file, use the default nvm version
if [[ ! $nvm_path = *[^[:space:]]* ]]; then
declare default_version;
default_version=$(nvm version default);
# If there is no default version, set it to `node`
# This will use the latest version on your machine
if [[ $default_version == "N/A" ]]; then
nvm alias default node;
default_version=$(nvm version default);
fi
# If the current version is not the default version, set it to use the default version
if [[ $(nvm current) != "$default_version" ]]; then
nvm use default;
fi
elif [[ -s $nvm_path/.nvmrc && -r $nvm_path/.nvmrc ]]; then
declare nvm_version
nvm_version=$(<"$nvm_path"/.nvmrc)
declare locally_resolved_nvm_version
# `nvm ls` will check all locally-available versions
# If there are multiple matching versions, take the latest one
# Remove the `->` and `*` characters and spaces
# `locally_resolved_nvm_version` will be `N/A` if no local versions are found
locally_resolved_nvm_version=$(nvm ls --no-colors "$nvm_version" | tail -1 | tr -d '\->*' | tr -d '[:space:]')
# If it is not already installed, install it
# `nvm install` will implicitly use the newly-installed version
if [[ "$locally_resolved_nvm_version" == "N/A" ]]; then
nvm install "$nvm_version";
elif [[ $(nvm current) != "$locally_resolved_nvm_version" ]]; then
nvm use "$nvm_version";
fi
fi
}
alias cd='cdnvm'
Cause there's no hook support in Bash, the solution above is ugly.
For zsh, put this into your $HOME/.zshrc
# place this after nvm initialization!
autoload -U add-zsh-hook
load-nvmrc() {
local node_version="$(nvm version)"
local nvmrc_path="$(nvm_find_nvmrc)"
if [ -n "$nvmrc_path" ]; then
local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")
if [ "$nvmrc_node_version" = "N/A" ]; then
nvm install
elif [ "$nvmrc_node_version" != "$node_version" ]; then
nvm use
fi
elif [ "$node_version" != "$(nvm version default)" ]; then
echo "Reverting to nvm default version"
nvm use default
fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc
A Better Solution
A better solution is to use nodenv. I'm not kidding, nodenv
is very different from nvm, and n.
nodenv
is a member of the rbenv
family. These version managers have big advantages over the others.
- It changes node version without modifying environment variable
PATH
time by time, because it uses shim executables. This makes it having a builtin support to switch node version automatically. - Auto version switch in
nodenv
doesn't have to be hooked onchpwd
to do periodical check for directory change. The version selection is delayed to whennode
command is executed. - The commands in
nodenv
are implemented in scripts. While, commands fromnvm
are implemented in functions, which means all the 4000+ line of code have to be parsed on shell startup and increases the shell init time dramatically.nodenv
initializes much faster.
References
- nodenv/nodenv
As pointed out in the GitHub issue thread related to this on the nvm
repository, you may run the following command in each of your Angular project folders:
$ node -v > .nvmrc
Note that you need to first switch to the right version of node in each of your projects, before running the command above.
What's happening in the command:
-
node -v
will out the current version ofnode
tostdout
. - The
>
symbol will thenredirecting
the output to a file called.nvmrc
(it will overwrite if something already exists with the same file name). - Read more bash redirections under the REDIRECTION section under the bash man page: https://linux.die.net/man/1/bash
When you cd
into your target directories, nvm
will now first read the file, and auto-switch to the correct version.