Node.js 版本管理与环境隔离
Node 项目最烦的就是版本不兼容——这个项目要 18,那个要 20,还有个老古董非得用 16。版本管理工具解决版本切换,pnpm/npm 解决依赖隔离,一次配好省得以后折腾。
相关文档:fnm (opens new window) | nvm (opens new window) | pnpm (opens new window) | corepack (opens new window)
# fnm — 更快的 Node 版本切换(推荐)
fnm (opens new window) 是 Rust 写的,和 nvm 功能一样但速度快几十倍。
# 安装
# macOS
brew install fnm
# Linux / WSL
curl -fsSL https://fnm.vercel.app/install | bash
# Windows
winget install Schniz.fnm
装完加到 shell 配置(~/.bashrc 或 ~/.zshrc):
eval "$(fnm env --use-on-cd)"
这行很关键:--use-on-cd 让你进项目目录时自动读 .nvmrc / .node-version 切版本。
# 基本使用
# 安装最新 LTS
fnm install --lts
# 安装指定版本
fnm install 20
# 切换版本
fnm use 18
fnm use 20
# 查看已安装版本
fnm list
# 查看远程可用版本
fnm list-remote
# 设置默认版本
fnm default 20
# 卸载版本
fnm uninstall 16
# fnm vs nvm
| 对比项 | nvm | fnm |
|---|---|---|
| 语言 | Bash | Rust |
| 切换速度 | 慢(每次 source 脚本) | 快(毫秒级) |
| Windows 支持 | 不支持(要用 nvm-windows) | 原生支持 |
| 自动切换 | 需要自己写 hook | --use-on-cd 内置 |
| .nvmrc 兼容 | 原生 | 兼容 |
结论:没历史包袱直接上 fnm。老项目用的 nvm 也不用急着换,功能完全一样,速度差异在开发中感知不大。
# nvm — Node 版本切换
# 安装
# curl 一键安装(访问不了就用代理)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
# 或者 wget
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
装完重启终端,或者手动 source 一下:
source ~/.bashrc
验证:
nvm --version
# 基本使用
# 安装最新 LTS 版本(推荐)
nvm install --lts
# 安装指定版本
nvm install 20.18.0
# 切换版本
nvm use 18
nvm use 20
# 查看已安装的版本
nvm ls
# 查看远程可用版本
nvm ls-remote
# 设置默认版本(新终端自动用这个)
nvm alias default 20
# 卸载某个版本
nvm uninstall 16
# 项目级自动切换
每个项目根目录放个 .nvmrc,写上需要的版本号:
# 在项目根目录执行
echo "20" > .nvmrc
# 以后进项目目录,一行搞定
nvm use
嫌每次手动 nvm use 麻烦?在 ~/.bashrc 末尾加这段,cd 进去自动切:
# 进入含 .nvmrc 的目录时自动切换 Node 版本
cdnvm() {
cd "$@" || return $?
nvm_path="$(nvm_find_up .nvmrc | tr -d '\n')"
if [[ -n "$nvm_path" ]]; then
nvm use
fi
}
alias cd='cdnvm'
# pnpm — 包管理 + 依赖隔离
npm/yarn 能干的 pnpm 都能干,而且更快、更省磁盘空间。最关键的是:每个项目的 node_modules 天然隔离,不会互相污染。
# 安装
# 方式一:用 corepack(Node 16.13+ 自带,推荐)
corepack enable
corepack prepare pnpm@latest --activate
# 方式二:npm 全局安装
npm install -g pnpm
# 方式三:独立脚本
curl -fsSL https://get.pnpm.io/install.sh | sh -
# 常用命令
# 安装依赖
pnpm install
# 添加包
pnpm add axios
pnpm add -D typescript # devDependencies
pnpm add -g pm2 # 全局安装
# 删除包
pnpm remove axios
# 运行脚本
pnpm dev
pnpm build
# 更新依赖
pnpm update
pnpm outdated # 查看过期的包
# 为什么选 pnpm
| 对比项 | npm | pnpm |
|---|---|---|
| 安装速度 | 慢 | 快(硬链接复用缓存) |
| 磁盘占用 | 每个项目一份完整的 node_modules | 全局 store,项目间共享 |
| 幽灵依赖 | 有(能 import 未声明的包) | 没有(严格的 node_modules 结构) |
| monorepo | 需要 lerna/nx | 原生 workspace 支持 |
# monorepo(pnpm workspace)
多个子项目放一起管理,共享依赖:
my-monorepo/
├── pnpm-workspace.yaml
├── package.json
├── packages/
│ ├── frontend/
│ ├── backend/
│ └── shared/
# pnpm-workspace.yaml
packages:
- "packages/*"
# 在根目录一次性安装所有子项目依赖
pnpm install
# 给指定子项目加包
pnpm --filter frontend add axios
# 所有子项目执行构建
pnpm -r build
# corepack — Node 自带的包管理器版本控制
Node 16.13+ 内置了 corepack,不需要手动装 yarn/pnpm,corepack 帮你管。
# 启用 corepack
corepack enable
# 指定项目用 pnpm
corepack prepare pnpm@latest --activate
# 指定项目用 yarn
corepack prepare yarn@latest --activate
# 项目 package.json 里写死版本,corepack 自动切换
{
"packageManager": "pnpm@9.12.0"
}
这样团队成员用的包管理器版本完全一致,不会有"我这能跑你那报错"的问题。
# .nvmrc + pnpm 组合工作流
实际项目里的推荐配置:
# 项目根目录
echo "20" > .nvmrc # Node 版本
pnpm init # 初始化 package.json
pnpm pkg set packageManager="pnpm@9.12.0" # 锁定 pnpm 版本
pnpm install # 安装依赖
新同事 clone 下来只需要:
nvm use # 自动读 .nvmrc 切 Node 版本
corepack enable # 启用 corepack
pnpm install # 自动读 packageManager 字段切 pnpm 版本
环境完全一致,没有多余操作。
上次更新: 2026/08/18, 01:07:41