用 nvm alias default version 更改預設的 node 版本,但 shell 重開後依然是原來的 node 版本
結論
根據官網 Automatically call nvm use,在 ~/.bashrc 檔案最後面加上
cdnvm() {
cd "$@";
nvm_path=$(nvm_find_up .nvmrc | tr -d '\n')
# 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'
cd $PWD
那麼,只要專案根目錄裡面,沒有用 .nvmrc 檔指定 node 版本,就會用 default 的版本。如果有 .nvmrc 檔的話,會優先使用 .nvmrc 檔指定 node 版本。
還沒做任何嘗試前的環境
作業系統:MacOS Big Sur 11.5.1
shell: bash
echo $NVM_DIR 印出來的東西:/Users/flora/.nvm
which node 印出來的東西: /Users/flora/.nvm/versions/node/v10.15.0/bin/node
which npm 印出來的東西:/Users/flora/.nvm/versions/node/v10.15.0/bin/npm
which iojs:(什麼都沒印出來)
npm config get prefix 印出來的東西:/Users/flora/.nvm/versions/node/v10.15.0
npm root -g 印出來的東西:/Users/flora/.nvm/versions/node/v10.15.0/lib/node_modules
nvm ls 印出來的東西:
-> v10.15.0
v10.24.1
v14.16.0
default -> 10.15.0 (-> v10.15.0)
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v14.16.0) (default)
stable -> 14.16 (-> v14.16.0) (default)
lts/* -> lts/fermium (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1
lts/erbium -> v12.22.6 (-> N/A)
lts/fermium -> v14.17.6 (-> N/A)
echo $PATH 印出來的東西:
/Users/flora/.pyenv/shims:
/Users/flora/.pyenv/bin:
/Users/flora/.nvm/versions/node/v10.15.0/bin:
/Users/flora/bin:
/usr/local/bin:
/Users/flora/.pyenv/plugins/pyenv-virtualenv/shims:
/usr/local/bin:
/usr/bin:
/bin:
/usr/sbin:
/sbin:
/Users/flora/Library/Python/3.9/bin:
/Users/flora/opt/anaconda3/bin:
/Users/flora/opt/anaconda3/condabin:
/Users/flora/.pyenv/shims:
/Users/flora/.pyenv/bin:
/Users/flora/.nvm/versions/node/v10.15.0/bin:
/Users/flora/bin:
/Users/flora/.local/bin:
/Users/flora/.local/bin
~/.bash_profile(跟 nvm 相關的地方在 20~22 行):
function parse_git_dirty {
if [[ $(git status 2> /dev/null | tail -n1) == "nothing to commit, working tree clean" ]]; then
echo "✔ "
else
echo "✘ "
fi
}
function git_branch {
ref=$(git symbolic-ref HEAD 2> /dev/null) || return;
echo "("$(parse_git_dirty)${ref#refs/heads/}") ";
}
if [ -f $HOME/.bashrc ]; then
source $HOME/.bashrc
fi
export PATH=$HOME/bin:/usr/local/bin:$PATH
export PS1='[\[\e[1;32m\]\w\[\e[0m\]] \[\e[1;36m\]$(git_branch)\[\e[0m\]$ '
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/flora/opt/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/Users/flora/opt/anaconda3/etc/profile.d/conda.sh" ]; then
. "/Users/flora/opt/anaconda3/etc/profile.d/conda.sh"
else
export PATH="/Users/flora/opt/anaconda3/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<
~/.bashrc(裡面只有設定跟 python 相關的東西):
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
export PATH="$PATH:/Users/flora/.local/bin"
問題描述
原本使用的 node 版本是 10.15.0。設定 nvm alias default 14.16.0,然後關掉終端機。重開終端機後 nvm ls 印出的東西
-> v10.15.0
v10.24.1
v14.16.0
default -> 14.16.0 (-> v14.16.0)
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v14.16.0) (default)
stable -> 14.16 (-> v14.16.0) (default)
lts/* -> lts/fermium (-> N/A)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1
lts/erbium -> v12.22.6 (-> N/A)
lts/fermium -> v14.17.6 (-> N/A)
default 是改成 14.16.0 了,但使用的依然是 10.15.0,而不是我期望的 14.16.0。我不想每次打開終端機都要輸入一次 nvm use default 來切換版本啊。
嘗試過的解決方式
參考 nvm keeps "forgetting" node in new terminal session
把 ~/.bash_profile 中跟 nvm 相關的地方,移到檔案最底下:
function parse_git_dirty {
if [[ $(git status 2> /dev/null | tail -n1) == "nothing to commit, working tree clean" ]]; then
echo "✔ "
else
echo "✘ "
fi
}
function git_branch {
ref=$(git symbolic-ref HEAD 2> /dev/null) || return;
echo "("$(parse_git_dirty)${ref#refs/heads/}") ";
}
if [ -f $HOME/.bashrc ]; then
source $HOME/.bashrc
fi
export PATH=$HOME/bin:/usr/local/bin:$PATH
export PS1='[\[\e[1;32m\]\w\[\e[0m\]] \[\e[1;36m\]$(git_branch)\[\e[0m\]$ '
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
# >>> conda initialize >>>
# !! Contents within this block are managed by 'conda init' !!
__conda_setup="$('/Users/flora/opt/anaconda3/bin/conda' 'shell.bash' 'hook' 2> /dev/null)"
if [ $? -eq 0 ]; then
eval "$__conda_setup"
else
if [ -f "/Users/flora/opt/anaconda3/etc/profile.d/conda.sh" ]; then
. "/Users/flora/opt/anaconda3/etc/profile.d/conda.sh"
else
export PATH="/Users/flora/opt/anaconda3/bin:$PATH"
fi
fi
unset __conda_setup
# <<< conda initialize <<<
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
存檔後重新開啟終端機,nvm ls 印出來的東西,沒有使用 default 的 14.16.0,依然是原本的 10.15.0。
echo $PATH 印出來的東西:
/Users/flora/.nvm/versions/node/v10.15.0/bin:
/Users/flora/.pyenv/shims:
/Users/flora/.pyenv/bin:
/Users/flora/bin:
/usr/local/bin:
/Users/flora/.pyenv/plugins/pyenv-virtualenv/shims:
/usr/local/bin:
/usr/bin:
/bin:
/usr/sbin:/sbin:
/Users/flora/Library/Python/3.9/bin:
/Users/flora/opt/anaconda3/bin:
/Users/flora/opt/anaconda3/condabin:
/Users/flora/.pyenv/shims:
/Users/flora/.pyenv/bin:
/Users/flora/.nvm/versions/node/v10.15.0/bin:
/Users/flora/bin:
/Users/flora/.local/bin:
/Users/flora/.local/bin
觀察修改前後 $PATH 的變化:「/Users/flora/.nvm/versions/node/v10.15.0/bin:」一樣是出現兩次,而且都是 10.15.0。不過第一次出現的時間提早了,從第三行提前到第一行。
繼續修改 ~/.bash_profile:在原本的 nvm 指令後面加上新的兩行(第 4~5 行),在 shell 裡面指定要使用預設的版本:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
NODE_DEFAULT_VERSION=$(<"$NVM_DIR/alias/default")
export PATH="$NVM_DIR/versions/node/$NODE_DEFAULT_VERSION/bin":$PATH
存檔後重新開啟終端機,nvm ls 印出來的東西,沒有使用 default 的 14.16.0,依然是原本的 10.15.0。
echo $PATH 印出來的東西:
/Users/flora/.nvm/versions/node/14.16.0/bin:
/Users/flora/.nvm/versions/node/v10.15.0/bin:
/Users/flora/.pyenv/shims:
/Users/flora/.pyenv/bin:
/Users/flora/bin:
/usr/local/bin:
/Users/flora/.pyenv/plugins/pyenv-virtualenv/shims:
/usr/local/bin:
/usr/bin:
/bin:
/usr/sbin:
/sbin:
/Users/flora/Library/Python/3.9/bin:
/Users/flora/opt/anaconda3/bin:
/Users/flora/opt/anaconda3/condabin:
/Users/flora/.pyenv/shims:
/Users/flora/.pyenv/bin:
/Users/flora/.nvm/versions/node/v10.15.0/bin:
/Users/flora/bin:
/Users/flora/.local/bin:
/Users/flora/.local/bin
觀察修改前後 $PATH 的變化:在最上方多了一行「/Users/flora/.nvm/versions/node/14.16.0/bin:」,裡面的版本是我想要用的沒錯,但是為什麼最後出現的不是你啊!另外那兩行咬定青山不放鬆的「/Users/flora/.nvm/versions/node/v10.15.0/bin:」到底是哪來的⋯⋯
which node 印出來的東西依然是 /Users/flora/.nvm/versions/node/v10.15.0/bin/node
說好的「在 $PATH 裡面排得越前面的,越優先使用」呢?難道你不是從 $PATH 去找要執行哪個版本的 node 的嗎? T口T
檢查 shell 語法中用到的 "$NVM_DIR/bash_completion" 檔案。檔案打開後⋯⋯更多的 shell 語法,一時之間也看不懂。搜尋到 bash-completion 這篇文章,看樣子好像是讓我們只要輸入指令開頭幾個字,按 tab 鍵就會自動幫我們寫完後面的指令。兇手應該不是他。
檢查 shell 語法中用到的 "$NVM_DIR/nvm.sh" 檔案,這是個非常長的檔案⋯⋯嗯算了我放棄。我先來試試看更新 nvm。按照官網的說法,輸入指令 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
終端機說
(base) [~] $ curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 14926 100 14926 0 0 12934 0 0:00:01 0:00:01 --:--:-- 12934
=> nvm is already installed in /Users/flora/.nvm, trying to update using git
=> => Compressing and cleaning up git repository
=> Appending nvm source string to /Users/flora/.bashrc
bash: line 414: /Users/flora/.bashrc: Permission denied
=> Appending bash_completion source string to /Users/flora/.bashrc
bash: line 421: /Users/flora/.bashrc: Permission denied
=> Close and reopen your terminal to start using nvm or run the following to use it now:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
好像是想要修改我的 ~/.bashrc 檔案但是失敗了。我猜他是想要要在 ~/.bashrc 裡面加上倒數那三行東西。不過那三行已經在我的 ~/.bash_profile 裡面了,我猜應該是沒關係。重新開啟終端機,node 依然不是使用 default 版本⋯⋯
根據官網,在專案根目錄放一個「.nvmrc」檔,裡面寫「v14.16.0」,然後在終端機寫 nvm use 就會使用那個版本。
官網說,為了讓電腦自動執行 nvm use ,要在 ~/.bashrc 裡面加這一段:
cdnvm() {
cd "$@";
nvm_path=$(nvm_find_up .nvmrc | tr -d '\n')
# 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'
cd $PWD
不過,我是把 nvm 相關指令放在 ~/.bash_profile 裡面,所以這一段我也是放在 ~/.bash_profile 裡面,變成這樣:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion
NODE_DEFAULT_VERSION=$(<"$NVM_DIR/alias/default")
export PATH="$NVM_DIR/versions/node/$NODE_DEFAULT_VERSION/bin":$PATH
cdnvm() {
cd "$@";
nvm_path=$(nvm_find_up .nvmrc | tr -d '\n')
# 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'
cd $PWD
然後重新打開終端機,就變成 .nvmrc 裡指定的版本了。
疑問:.nvmrc 要放到 .gitignore 裡嗎?我猜應該要放,因為只是要指定本地專案使用的 node 版本。
仔細看官網提供的那段程式碼,裡面有段註解說「# If there are no .nvmrc file, use the default nvm version」。如果沒有 .nvmrc 檔,會使用預設版本!這樣就不用擔心「.nvmrc 要放到 .gitignore 裡嗎?」的事了。
Shell 語法參考資料
Comments
Post a Comment