Featured image of post Node.js 与 NVM 版本管理:从单版本到多版本共存

Node.js 与 NVM 版本管理:从单版本到多版本共存

Node.js 几乎是前端工程的「地基」——Webpack/Vite/Yarn/ESLint 全部跑在它上面。本文从 Node 版本历史讲起,串起 nvm/nvm-windows 的安装、配置、镜像加速、.nvmrc 锁定、npm 全局路径规划、cnpm/treer 配套工具,最后给一个「物理机手动打包发布」脚本示例。

为什么写这篇:2016 年的前端项目还经常"卡在 Node 版本"——A 项目要 Node 6、B 项目要 Node 8、C 项目要 Node 10……NVM(Node Version Manager)让一台机器同时装多个 Node 版本、随时切换。本文用 macOS/Linux(nvm-sh)和 Windows(nvm-windows)两条线讲解,最后给一个企业内网"从 Git 拉代码 → 构建 → 打 Docker 镜像 → kubectl apply"的全套脚本。

适用读者:刚装 Node 的新人;要维护多个不同 Node 版本项目的工程师;企业内网打包流水线维护者。

前置知识:会用命令行;知道 npm install 是什么。

目录

  1. Node.js 的版本发布节奏
  2. Linux/macOS:nvm-sh 安装与使用
  3. Windows:nvm-windows 安装与配置
  4. 镜像加速:解决 npm 装包龟速
  5. npm 全局路径规划
  6. VSCode 智能提示与配套工具
  7. 物理机手动打包发布全流程

1. Node.js 的版本节奏

Node.js 采用 SemVer(语义化版本) + LTS(长期支持) 双重节奏:

版本类型说明例子
Current(奇数大版本)6 个月活跃开发期,包含新特性17、19、21、23
Active LTS(偶数大版本)12 个月活跃支持期,bugfix + 安全更新18 LTS、20 LTS、22 LTS
Maintenance LTS18 个月维护期,仅修安全漏洞16 → 2023-09 终止
End-of-Life不再提供任何更新,生产环境必须避免14、17、19

选型建议:生产项目永远用 Active LTS。本文写作时的 LTS 主流是 Node 20.x / 22.x

Node 重大里程碑:

版本年份关键变化
0.102013第一个被广泛使用的稳定版
4.x2015-090.12 → 4.0 的大版本合并(io.js 回流)
6.x2016-04LTS 时代开启
8.x2017-05LTS + npm 5 + async_hooks
10.x2018-04HTTP/2、n-api 稳定
12.x2019-04V8 升级、ES Modules 试验
14.x2020-04首次原生支持 ES Modules、V8 8.1
16.x2021-04V8 9.0、fs/promises 稳定
18.x2022-04内置 fetch、test runner
20.x2023-04权限模型、Single Executable Applications
22.x2024-04内置 WebSocket、类型剥离

2. Linux/macOS:nvm-sh 安装与使用

2.1 完全卸载旧 Node

1
2
3
4
5
6
7
# Ubuntu / Debian
sudo apt remove --purge nodejs npm -y
sudo apt autoremove -y
sudo apt autoclean

# macOS(用 Homebrew 装的)
brew uninstall node

2.2 一行命令装 nvm

1
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.4/install.sh | bash

脚本会自动在 ~/.bashrc / ~/.zshrc / ~/.config/fish/config.fish 里追加:

1
2
export NVM_DIR="$([ -z "${XDG_CONFIG_HOME-}" ] && printf %s "${HOME}/.nvm" || printf %s "${XDG_CONFIG_HOME}/nvm")"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"

让配置生效:

1
source ~/.zshrc    # 或 source ~/.bashrc

2.3 fish shell 用户

fish shell 用户可以装 nvm.fish 插件(基于 Fisher 插件管理器):

1
2
3
4
5
6
7
8
9
# 装 Fisher
curl -sL https://raw.githubusercontent.com/jorgebucaran/fisher/main/functions/fisher.fish | source && fisher install jorgebucaran/fisher

# 装 nvm.fish
fisher install jorgebucaran/nvm.fish

# 卸载
fisher list
fisher remove jorgebucaran/nvm.fish

2.4 装指定版本

 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
# 列出所有可装的版本
nvm ls-remote

# 装最新版 LTS
nvm install --lts

# 装指定版本
nvm install v22.21.1
nvm install 20
nvm install 18.18.2

# 列出已装的版本
nvm ls
#  ->     v18.18.2
#  ->     v20.12.0
#  ->     v22.21.1
# default -> lts/* (-> v22.21.1)

# 切换版本
nvm use 20.12.0
nvm use 18.18.2

# 查看当前版本
node -v
npm -v

2.5 用 .nvmrc 锁定项目版本

在项目根目录放一个 .nvmrc

1
20.12.0

之后进项目就 nvm use,nvm 会自动读 .nvmrc 切到对应版本。

1
2
# 还可以自动 install
nvm install   # 读 .nvmrc,没有就装 lts

2.6 镜像加速(推荐)

nvm-sh 装 Node 时默认从 nodejs.org 下载,国内很慢。可以设镜像:

1
2
3
4
5
# 临时(本次命令)
NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node nvm install 20

# 永久(写到 shell 配置)
export NVM_NODEJS_ORG_MIRROR=https://npmmirror.com/mirrors/node

3. Windows:nvm-windows 安装与配置

Windows 上没有 nvm-sh,但有社区维护的 coreybutler/nvm-windows

3.1 下载与安装

从 GitHub releases 下载最新 nvm-setup.zip(或免安装版 nvm-noinstall.zip),注意:必须以管理员权限运行 install.cmd

3.2 配置 settings.txt

%NVM_HOME%\settings.txt(默认在 C:\Users\<用户>\AppData\Roaming\nvm\):

1
2
3
4
5
6
root: <DEV_DIR>nvm
path: <DEV_DIR>nodejs
arch: 64
proxy: none
node_mirror: https://npmmirror.com/mirrors/node/
npm_mirror: https://npmmirror.com/mirrors/npm/

3.3 环境变量

变量
NVM_HOME<DEV_DIR>nvm
NVM_SYMLINK<DEV_DIR>nodejs
PATH追加 %NVM_HOME%;%NVM_SYMLINK%;

Why 单独设 SYMLINK:nvm-windows 用 junction 软链接把当前激活的 Node 目录指向 NVM_SYMLINK,命令行的 node / npm 走 PATH 就能找到。

3.4 日常使用

1
2
3
4
5
6
nvm version                  # 查看 nvm 版本
nvm list available           # 列出可装的版本
nvm install 22.21.1          # 装 Node 22.21.1
nvm use 22.21.1              # 切换
nvm ls                       # 已装列表
nvm upgrade                  # 自更新 nvm 自身

3.5 离线安装

公司内网完全没外网时,先在有外网的机器上下好 node-v22.21.1-win-x64.zip

1
2
3
4
5
下到 <DEV_DIR>nvm\v22.21.1\
├── node.exe
├── npm.cmd
├── npx.cmd
└── node_modules\

文件夹名必须是 <version> 格式(v22.21.1)。然后 nvm use 22.21.1 即可。


4. 镜像加速:解决 npm 装包龟速

4.1 设置 npm 镜像

1
2
3
4
5
6
7
8
# 临时
npm install <pkg> --registry=https://registry.npmmirror.com

# 永久
npm config set registry https://registry.npmmirror.com

# 验证
npm config get registry

4.2 nrm:多镜像一键切换

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
npm install -g nrm

nrm ls
#  npm ---------- https://registry.npmjs.org/
#  yarn --------- https://registry.yarnpkg.com/
#  tencent ------ https://mirrors.cloud.tencent.com/npm/
#  cnpm --------- https://r.cnpmjs.org/
#  taobao ------- https://registry.npmmirror.com/

nrm use taobao
nrm use cnpm

4.3 cnpm:完全镜像版 npm

1
2
npm install -g cnpm --registry=https://registry.npmmirror.com
cnpm install lodash   # 走国内 CDN,比 npm 快 5-10 倍

4.4 常见代理配置

1
2
3
4
5
6
7
# 命令行
$ npm config set proxy http://127.0.0.1:1081
$ npm config set https-proxy http://127.0.0.1:1081

# 环境变量(推荐,重启 shell 失效)
export npm_config_proxy=http://127.0.0.1:1081
export npm_config_https_proxy=http://127.0.0.1:1081

小贴士:Windows 11 上 npm.cmd 调全局安装时,prefix -g 在新 Node 18+ 下有 bug。可以改:

1
sed -i "s|prefix -g|prefix --location=global|g" "$(which npm.cmd)"

或直接用 npm install -g xxx——18+ 已默认 --location=global,这条 hack 主要针对 16 及以下。


5. npm 全局路径规划

默认情况下,npm 把全局包装到 %APPDATA%\npm(Windows)或 /usr/local/lib/node_modules(macOS/Linux),污染系统盘且与 Node 版本绑定。

5.1 自定义全局路径

1
2
3
4
5
6
# 自定义 prefix
npm config set prefix "<NPM_GLOBAL_DIR>"

# 在 PATH 中加 %NPM_HOME%
set NPM_HOME=<NPM_GLOBAL_DIR>
set PATH=%NPM_HOME%;%PATH%

这样全局装的所有包都在 <NPM_GLOBAL_DIR>重装 Node 不会丢全局包

5.2 全局装包管理

1
2
3
4
5
6
7
8
9
# 查看已装的全局包
npm list -g --depth=0

# 卸载
npm uninstall -g <pkg>

# 手动清(极少见)
# Windows: 删除 C:\Users\<user>\AppData\Roaming\npm\node_modules
# Linux:   删除 /usr/local/lib/node_modules/<pkg>

6. VSCode 智能提示与配套工具

6.1 @types/node

在项目里装 @types/node 后,VSCode 能智能提示 Node 内置模块(fspathprocess)和环境变量:

1
npm install --save-dev @types/node

6.2 运行脚本

1
2
3
node serve.js
node --inspect serve.js       # 开启调试端口 9229
node --inspect-brk serve.js   # 第一行就断点

6.3 treer:项目结构可视化

1
2
npm install -g treer
treer -e tree.txt -i "/node_modules|.git|.idea/"

会输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
D:/workspace/github/my-app
├── dist
├── node_modules
├── public
├── src
│   ├── App.vue
│   ├── main.ts
│   └── router
│       └── index.ts
├── index.html
├── package.json
└── vite.config.ts

方便在博文/Issue/聊天里分享目录。


7. 物理机手动打包发布全流程

公司内网没有 CI/CD 时,“开发把代码推上 Git → 运维在跳板机上拉代码 → 构建 → 打镜像 → 更新 K8s” 是常见流程。下面是一个典型脚本(所有内部信息已脱敏):

 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
41
42
43
44
45
46
47
48
49
50
51
# ============ 1. 在构建机(127)执行 ============
# 用户名/密码:内部账号
cd /home/tmp

# 拉代码
git clone http://<GIT_HOST>:<PORT>/<ORG>/safety_microservices_vue.git
cd safety_microservices_vue/
git checkout -b hnTest
git pull origin hnTest

# 清理上次构建
rm -rf dist/

# 切 Node 版本
nvm use 18.18.2

# 用国内镜像
npm config set registry https://registry.npmmirror.com/
yarn config set registry https://registry.npmmirror.com/

# 清缓存重装
yarn cache clean --force
rm -rf node_modules
yarn
yarn build

# ============ 2. 同步到目标机(253)===========
cd /root/frontend
rm -rf *

# 用 sshpass 免密同步
sshpass -p <REDACTED> \
rsync -e 'ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null' \
  -avz --progress \
  root@<BUILD_HOST>:/home/tmp/safety_microservices_vue/dist /root/frontend/

mv dist html

# ============ 3. 打 Docker 镜像 ============
cat << "EOF" > Dockerfile
FROM <PRIVATE_REGISTRY>/base/bitnami/nginx:1.27.0-debian-12-r3
COPY html /app
EOF

docker build -t <PRIVATE_REGISTRY>/library/safety-frontend/pre:2025-08-18_001 .
docker push <PRIVATE_REGISTRY>/library/safety-frontend/pre:2025-08-18_001

# ============ 4. 改 K8s yaml 并应用 ============
sed -i "s|image:.*|image: <PRIVATE_REGISTRY>/library/safety-frontend/pre:2025-08-18_001|" \
  /data/k8scnf/safety-hnpre/11frontend.yaml
kubectl apply -f /data/k8scnf/safety-hnpre/11frontend.yaml

这种"半自动"流程的痛点

  1. 任何一步失败要人工介入
  2. 镜像 tag 写死在 yaml 里,回滚要 git history
  3. 没有镜像扫描、签名、版本元数据

改进方向:把这条脚本拆成 GitLab CI / Jenkins Pipeline 的 stage,加 docker scan(trivy)、Helm Chart 管理版本。


小结

Node 装包是前端所有事的"前置依赖"。本文核心要点:

  1. 生产用 LTS(写作时是 Node 20/22),绝不用奇数版
  2. 多版本用 NVM(Linux/macOS)或 nvm-windows(Windows),.nvmrc 锁版本
  3. 国内必设镜像registry.npmmirror.com 或 cnpm
  4. npm 全局路径自定义,避免污染 C 盘或系统目录
  5. 物理机打包流程是"从 Git 到 K8s"的手动版,能跑但迟早要 CI/CD 化

参考资料


2024+ 视角:Node 22 LTS、pnpm 主导、Bun/Deno 三足鼎立

Node 22 LTS(2024-10 GA)核心变化

  • 内置 WebSocket 客户端globalThis.WebSocket 浏览器 API 移植,Node 服务端直接用
  • 内置 node:test runner:不再依赖 Jest / Mocha 也能跑单测
  • 权限模型(稳定)--permission --allow-fs-read=./src 限制 Node 进程的 FS/网络/子进程权限
  • 类型剥离(Type Stripping)node --experimental-strip-types app.ts 直接跑 TS 文件
  • V8 12.4 升级:原生支持 Array.fromAsync / Error.cause 改进
1
2
3
4
5
# Node 22 一行跑 TS
node --experimental-strip-types app.ts

# 限制权限运行
node --permission --allow-fs-read=. --allow-fs-write=./dist app.js

Node 22 → Node 23 → Node 24 路线图

  • Node 23(2024-10 Current)WebSocket 稳定、node:fs 性能优化
  • Node 24(2025-04 LTS):内置 require(esm) 默认开启、V8 12.6npm 11
  • Node 25(2025-10 Current):实验性 HTTP/3、QUIC

pnpm 9.x 主导企业市场

pnpm 已成 2024+ 企业前端标配——比 npm 快 2-3 倍、磁盘占用节省 70%:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 装 pnpm
npm install -g pnpm@9

# 装依赖(比 npm 快 2-3 倍)
pnpm install

# monorepo 经典用法
pnpm -r add lodash
pnpm --filter my-app build
pnpm --filter my-app test

pnpm 核心优势

  • 硬链接 + 符号链接:项目间共享 node_modules 里的文件,磁盘省 70%
  • monorepo 原生支持pnpm-workspace.yaml
  • 依赖隔离更严:默认阻止"幽灵依赖"——只用 package.json 里声明的包
  • 比 yarn 快、比 lerna 简单

Bun 1.x 2024+ 现状

Bun 是 Zig 写的 JavaScript 运行时——主打"Node 替代":

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 装 Bun
curl -fsSL https://bun.sh/install | bash

# 直接跑 TS
bun run app.ts

# 装依赖(比 npm 快 25 倍)
bun install

# 内置 SQLite / HTTP server / 打包器
bun --hot app.ts
维度Node 22 LTSBun 1.xDeno 2
启动速度3x 快2x 快
装包速度npm 11 一般25x 快1x
TS 支持实验性 --strip-types原生原生
API 兼容-95% Node 兼容Deno 原生
生产稳定较新
生态最大增长中中等

选型

  • 传统企业(稳):Node 22 LTS + pnpm 9
  • 新项目(性能优先)Bun 1.x —— 启动快 3 倍、装包快 25 倍
  • Deno 强项:边缘计算(Deno Deploy)+ 安全沙箱

Node 测试生态 2024+

1
2
3
4
5
6
7
8
# Node 22 内置 test runner
node --test

# 第三方主流
vitest          # 2024+ 最快(基于 esbuild)
node:test       # 内置
jest            # 老牌
playwright      # E2E
1
2
3
4
5
6
7
// Node 22 内置 test runner 示例
import { test } from 'node:test';
import assert from 'node:assert/strict';

test('adds 1 + 2', () => {
    assert.equal(1 + 2, 3);
});

NVM 2024+ 替代品

  • fnm(Fast Node Manager):Rust 写的,比 nvm 快 10 倍
  • volta:JavaScript 写的,团队级版本锁定
  • nvm-windows 仍是 Windows 唯一主流
1
2
3
4
# fnm(2024+ 推荐)
curl -fsSL https://fnm.vercel.app/install | bash
fnm install 22
fnm use 22

npm 11.x 关键变化

  • Workspaces 增强npm install -w @myorg/pkg 直接给子包装
  • 内置 SBOM 生成npm sbom 输出 CycloneDX / SPDX 格式
  • npm exec 替代 npx 语义更清晰
  • Lockfile v3package-lock.json 格式变化,更安全

Vite 6 + esbuild 2024+

1
2
3
4
# Vite 6(2024-11 GA)
npm create vite@latest my-app -- --template vue-ts
cd my-app
pnpm dev
  • Vite 6 引入 Environment API(SSR / SPA 统一 API)
  • Rolldown(Rust 写的 Rollup 替代)2024 进入 alpha——比 Rollup 快 10 倍
  • esbuild 0.24+ 完全稳定,TypeScript / JSX 编译首选

前端框架 2024+ 状态

框架2024+ 状态
React 19编译器优化、Server Components GA
Vue 3.5响应式系统重写、性能 +50%
Svelte 5Runes 语法(编译时反应性)+ 体积 -30%
Solid.js 1.92024 性能 SOTA
Astro 5内容驱动 + Island 架构
Next.js 15React 19 + Turbopack GA
Nuxt 3.14Vue 3.5 + Nitro 2.10

2024+ 推荐组合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
企业前端项目(稳)
├── Node 22 LTS(2024-10 GA)
├── pnpm 9.x(依赖管理)
├── Vite 6(构建)
├── TypeScript 5.6+(类型)
├── Vitest(测试)
├── ESLint 9 + Prettier 3(代码风格)
└── Playwright(E2E)

新项目(性能优先)
├── Bun 1.x(运行时)
├── Vite 6 + Rolldown alpha
├── TypeScript 5.6+
└── Solid.js / Svelte 5(轻量框架)
使用 Hugo 构建
主题 StackJimmy 设计