很多同學在選擇 node 的版本管理工具時,可能第一時間就直接使用了 nvm,一般不會再去調研另一個工具 n,更沒有閒情去了解這兩者的特性和差異。畢竟工具能用就行,沒必要搞清其運作機制。
是的,我也不例外,然而直到有一天……
引子
我本機安裝著 nvm,而 node 本來一直執行在 0.x 的老版本上。後來為了跑 ES6,我將 node 切換到 4.x 的版本,並且把老版本給刪掉了。
然後我就碰到了兩個問題。一是 WebStorm 報錯說找不到 node 直譯器了。我只好去設定裡面重新設定一番直譯器的路徑:
在我的記憶中,WebStorm 預設不需要設定 node 路徑,它會去找 /usr/local/bin
,即通常的 node 命令位置。而一旦使用 nvm 來安裝和管理 node,甚至頻繁切換的話,我們就得 手動地 指定 node 路徑。
而且是如此硬編碼的路徑(硬編碼了版本號),真不優雅……
第二個問題是,我曾經在全域性安裝的各種 node 模組們全都需要重新安裝,因為全域性模組被安裝在每個 node 版本自己的沙箱中,因此它們和老版本的 node 一起被埋葬了。
事實上,這就是 nvm 的特性,然而喜不喜歡它則是另一回事兒了。
不管如何,由於發生了這些個問題,我決定稍微深入瞭解一下情況。
nvm 和 n
在 node 的版本管理工具中,nvm 自然聲名遠揚,然而我們也不能忘了來自 TJ 的 n。這兩種,是目前最主流的方案。
關於這兩個工具如何安裝和使用,這裡不再贅言,請見它們各自的主頁:
接下來我們著重關注一下 nvm 和 n 的運作機制和特性。
n
n 是一個需要全域性安裝的 npm package。
1 |
npm install -g n |
這意味著,我們在使用 n 管理 node 版本前,首先需要一個 node 環境。我們或者用 Homebrew 來安裝一個 node,或者從官網下載 pkg 來安裝,總之我們得先自己裝一個 node —— n 本身是沒法給你裝的。
然後我們可以使用 n 來安裝不同版本的 node。
在安裝的時候,n 會先將指定版本的 node 儲存下來,然後將其複製到我們熟知的路徑/usr/local/bin
,非常簡單明瞭。當然由於 n 會操作到非使用者目錄,所以需要加 sudo
來執行命令。
所以這樣看來,n 在其實現上是一個非常易理解的方案。
nvm
我們再來看 nvm。不同於 n,nvm 不是一個 npm package,而是一個獨立軟體包。這意味著我們需要單獨使用它的安裝邏輯:
1 |
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.29.0/install.sh | bash |
或者使用 Homebrew 來安裝。安裝完後,還需要修改一下 shell 配置(~/.zshrc
or whatever),具體參見官方文件。
然後我們可以使用 nvm 來安裝不同版本的 node。
在安裝的時候,nvm 將不同的 node 版本儲存到 ~/.nvm/<version>/
下,然後修改$PATH
,將指定版本的 node 路徑加入,這樣我們呼叫的 node
命令即是使用指定版本的 node。
nvm 顯然比 n 要複雜一些,但是另一方面,由於它是一個獨立軟體包,因此它和 node 之間的關係看上去更合乎邏輯:nvm 不依賴 node 環境,是 node 依賴 nvm;而不像 n 那樣產生類似迴圈依賴的問題。
如何選擇?
這樣看下來,nvm 和 n 的差異還是比較大的,具體體現在:
- 安裝簡易度。nvm 安裝起來顯然是要麻煩不少;n 這種安裝方式更符合 node 的慣性思維。見仁見智吧。
- 系統支援。注意, nvm 不支援 Windows。
- 對全域性模組的管理。n 對全域性模組毫無作為,因此有可能在切換了 node 版本後發生全域性模組執行出錯的問題;nvm 的全域性模組存在於各自版本的沙箱中,切換版本後需要重新安裝,不同版本間也不存在任何衝突。
- 關於 node 路徑。n 是萬年不變的
/usr/local/bin
;nvm 需要手動指定路徑。
所以,如何選擇?真心見仁見智了,不過這裡可以給出大體的建議:
- 如果你使用 Windows,那沒得選了,使用 n,或者換一臺 Mac。
- 如果你會頻繁切換 node 版本(比如本地經常測試最新版的特性,同時又要兼顧程式碼在生產環境的相容性),那麼從全域性模組相容性的角度考慮,只能使用 nvm。
- 如果你是一個輕量級的使用者,不需要擔心相容性的問題,更關心 node 安裝和使用上的體驗,那麼選擇 n。
你如果要問,樓主最終選用了誰?我會說,我選擇了更流行的那一個。
引用
題圖:櫟樹主幹產生的眾多分支(Oak Tree Branches)。然而我們通常只關心它的葉子節點。
花絮:我之所以選擇使用 nvm 而不遷移到 n,這其中的原因是及其複雜的 —— 唔……只是因為我不想再刪掉重灌一遍。