Mac 開啟專案時,自動使用 nvm use 切換到專案的 Node 版本

nvm auto use

前言

身為一名 Node.js 相關的開發者,常常會遇到需要切換 Node.js 版本的情況,但是我們每個專案所使用的 Node.js 都不同,因此就很容易忘記切換版本,所以這一篇就要來記錄一下如何在 Mac 上開啟專案時,就自動使用 nvm 切換 Node 版本。

前置動作

這邊有幾件事情必須先告知,你要開始使用這一篇往下設定之前,你必須先透過我的底下兩篇文章設定過 zsh、nvm,如果你還沒有設定過,建議你先設定完再繼續往下閱讀,否則有很高機會遇到一些奇怪的問題哩

如果你確定你本身已經電腦有安裝 nvm 並且有設定過 zsh(oh-my-zsh),那麼就可以繼續往下閱讀囉!

安裝 zsh-nvm

那麼如前提來講,我們開發的專案每一個 Node.js 版本都不同,而我們 nvm 所預設的 Node.js 版本可能也不同,例如專案所需要使用的版本是 18.17.0,但我 nvm 預設版本是 16.15.0,那麼就有可能發生忘記使用 nvm use 18.17.0 的情況,因此我們可以透過 zsh-nvm 來幫我們自動切換版本。

首先 zsh-nvm 官方文件來講,你可以使用以下方式安裝:

  • antigen
  • zplug
  • zgen
  • 手動
  • 作為 oh-my-zsh 自定義套件

那麼這邊我就會以「As an Oh My ZSH! custom plugin」來安裝,因為我本身就是使用 oh-my-zsh 所以我就直接使用這個方式。

首先我們先打開終端機輸入以下將 zsh-nvm 安裝到 oh-my-zsh 的自定義套件資料夾:

1
git clone https://github.com/lukechilds/zsh-nvm ~/.oh-my-zsh/custom/plugins/zsh-nvm

接著找到 ~/.zshrc 這個檔案,並且在 plugins 這個參數中加入 zsh-nvm

1
2
3
4
5
6
7
8
9
10
plugins=( 
git
# other plugins...
zsh-autosuggestions
zsh-syntax-highlighting
# 加入底下這一行
zsh-nvm
)

source $ZSH/oh-my-zsh.sh

Note
請注意 source $ZSH/oh-my-zsh.sh 一定要在 plugins 這個參數的下面,否則會出現錯誤。

最後你要在 source $ZSH/oh-my-zsh.sh 之前加入以下這一行:

1
export NVM_AUTO_USE=true

所以會變成以下這樣:

1
2
3
4
5
6
7
8
9
10
11
12
plugins=( 
git
# other plugins...
zsh-autosuggestions
zsh-syntax-highlighting
zsh-nvm
)

# 自動切換 nvm 版本
export NVM_AUTO_USE=true

source $ZSH/oh-my-zsh.sh

接著這時候你只要關閉終端機並重新開啟,就可以了。

建立 .nvmrc

這時候你可能很興奮地去打開了你的專案,這時候你可能會想說…

「為什麼我的終端機還是沒有依據專案自動切換 Node.js 版本啊?」

因為你還缺少一個東西,也就是 .nvmrc

nvmrc

你只需要在專案的根目錄下建立這個檔案,並填入你要切換的版本號就可以了,例如…

1
20.8.1

Note
基本上版本號就跟你在終端機輸入 nvm install 時所看到的版本號一樣哩。

這邊我也提供指令的方式建立 .nvmrc

1
echo "20.8.1" > .nvmrc

這樣子你每次打開終端機時,就會自動切換到 20.8.1 這個版本了!

自動切換

Powerlevel10k 出現警告?

如果你有使用 Powerlevel10k 的話,話會出現警告

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
[WARNING]: Console output during zsh initialization detected.

When using Powerlevel10k with instant prompt, console output during zsh
initialization may indicate issues.

You can:

- Recommended: Change ~/.zshrc so that it does not perform console I/O
after the instant prompt preamble. See the link below for details.

* You will not see this error message again.
* Zsh will start quickly and prompt will update smoothly.

- Suppress this warning either by running p10k configure or by manually
defining the following parameter:

typeset -g POWERLEVEL9K_INSTANT_PROMPT=quiet

* You will not see this error message again.
* Zsh will start quickly but prompt will jump down after initialization.

- Disable instant prompt either by running p10k configure or by manually
defining the following parameter:

typeset -g POWERLEVEL9K_INSTANT_PROMPT=off

* You will not see this error message again.
* Zsh will start slowly.

- Do nothing.

* You will see this error message every time you start zsh.
* Zsh will start quickly but prompt will jump down after initialization.

For details, see:
https://github.com/romkatv/powerlevel10k/blob/master/README.md#instant-prompt

-- console output produced during zsh initialization follows --

這個問題是因為我們在 ~/.zshrc 中加入了 export NVM_AUTO_USE=true 這個參數,而這個參數會在終端機開啟時自動切換 Node.js 版本,因此會在終端機開啟時輸出一些資訊,而這個問題在 zsh-nvm 的 issue 也有被提出,但我目前好像也沒看到相關的解決方案就是了。

目前最簡單方式就是你在 ~/.zshrc 中加入以下這行:

1
typeset -g POWERLEVEL9K_INSTANT_PROMPT=off

就可以解決,只需要在 Powerlevel10k instant prompt 之前就好,如下:

1
2
3
4
typeset -g POWERLEVEL9K_INSTANT_PROMPT=off # 加入這一行
if [[ -r "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh" ]]; then
source "${XDG_CACHE_HOME:-$HOME/.cache}/p10k-instant-prompt-${(%):-%n}.zsh"
fi

不使用 zsh-nvm 方式

其實自動切換 nvm 的程式碼在官方文件上本身就有提供了,只是我們需要自己手動加入,如果你不喜歡安裝 zsh-nvm 之後的解決方式,那你就可以考慮直接使用官方的方式。

首先請你將以下程式碼加入 ~/.zshrc,建議貼在最後

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# ... 前面是其他程式碼

# 自動切換 nvm 版本
autoload -U add-zsh-hook

load-nvmrc() {
local nvmrc_path
nvmrc_path="$(nvm_find_nvmrc)"

if [ -n "$nvmrc_path" ]; then
local nvmrc_node_version
nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

if [ "$nvmrc_node_version" = "N/A" ]; then
nvm install
elif [ "$nvmrc_node_version" != "$(nvm version)" ]; then
nvm use
fi
elif [ -n "$(PWD=$OLDPWD nvm_find_nvmrc)" ] && [ "$(nvm version)" != "$(nvm version default)" ]; then
echo "Reverting to nvm default version"
nvm use default
fi
}

add-zsh-hook chpwd load-nvmrc
load-nvmrc

接著一樣會出現 Powerlevel10k 的警告,這時候我們只需要稍微修改一下官方的程式碼去除輸出的資訊就可以了,修改後的程式碼如下:

(底下我也針對程式碼增加註解)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# ... 前面是其他程式碼

# 自動切換 nvm 版本

## 自動載入 Zsh hook 函式庫
autoload -U add-zsh-hook

## 宣告 load-nvmrc 函式
load-nvmrc() {
## 宣告 nvmrc_path 變數,紀錄 .nvmrc 檔案路徑
local nvmrc_path
## 使用 nvm_find_nvmrc 函式尋找 .nvmrc 檔案
nvmrc_path="$(nvm_find_nvmrc)"

## 如果有找到 .nvmrc 檔案
if [ -n "$nvmrc_path" ]; then
## 宣告 nvmrc_node_version 變數,紀錄 .nvmrc 檔案中的 Node.js 版本
local nvmrc_node_version
## 使用 nvm version 函式取得目前的 Node.js 版本
nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")

## 如果 .nvmrc 檔案中的 Node.js 版本是 N/A,就安裝,意旨 nvm 沒有這個版本
if [ "$nvmrc_node_version" = "N/A" ]; then
## 安裝特定 Node.js 版本
nvm install
## 如果 .nvmrc 檔案中的 Node.js 版本不是目前的 Node.js 版本,就切換到 .nvmrc 檔案中的 Node.js 版本
elif [ "$nvmrc_node_version" != "$(nvm version)" ]; then
## 切換到 .nvmrc 檔案中的 Node.js 版本,並靜音輸出
nvm use > /dev/null
fi

## 如果沒有找到 .nvmrc 檔案,就使用 nvm_find_nvmrc 函式尋找上一層目錄的 .nvmrc 檔案,如果有找到並且目前的 Node.js 版本不是預設版本,就切換到預設版本
elif [ -n "$(PWD=$OLDPWD nvm_find_nvmrc)" ] && [ "$(nvm version)" != "$(nvm version default)" ]; then
## 切換到預設版本,並靜音輸出
nvm use default > /dev/null
fi
}

add-zsh-hook chpwd load-nvmrc
load-nvmrc

只需要在 nvm use 後面加入 > /dev/null 就可以避免輸出資訊,這樣就不會再噴 Powerlevel10k 哩。

Liker 讚賞

這篇文章如果對你有幫助,你可以花 30 秒登入 LikeCoin 並點擊下方拍手按鈕(最多五下)免費支持與牡蠣鼓勵我。
或者你可以也可以請我「喝一杯咖啡(Donate)」。

Buy Me A Coffee Buy Me A Coffee

Google AD

撰寫一篇文章其實真的很花時間,如果你願意「關閉 Adblock (廣告阻擋器)」來支持我的話,我會非常感謝你 ヽ(・∀・)ノ