很多同学在选择 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,这其中的原因是及其复杂的 —— 唔……只是因为我不想再删掉重装一遍。