为什么写这篇: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 是什么。
目录
- Node.js 的版本发布节奏
- Linux/macOS:nvm-sh 安装与使用
- Windows:nvm-windows 安装与配置
- 镜像加速:解决 npm 装包龟速
- npm 全局路径规划
- VSCode 智能提示与配套工具
- 物理机手动打包发布全流程
1. Node.js 的版本节奏
Node.js 采用 SemVer(语义化版本) + LTS(长期支持) 双重节奏:
| 版本类型 | 说明 | 例子 |
|---|
| Current(奇数大版本) | 6 个月活跃开发期,包含新特性 | 17、19、21、23 |
| Active LTS(偶数大版本) | 12 个月活跃支持期,bugfix + 安全更新 | 18 LTS、20 LTS、22 LTS |
| Maintenance LTS | 18 个月维护期,仅修安全漏洞 | 16 → 2023-09 终止 |
| End-of-Life | 不再提供任何更新,生产环境必须避免 | 14、17、19 |
选型建议:生产项目永远用 Active LTS。本文写作时的 LTS 主流是 Node 20.x / 22.x。
Node 重大里程碑:
| 版本 | 年份 | 关键变化 |
|---|
| 0.10 | 2013 | 第一个被广泛使用的稳定版 |
| 4.x | 2015-09 | 0.12 → 4.0 的大版本合并(io.js 回流) |
| 6.x | 2016-04 | LTS 时代开启 |
| 8.x | 2017-05 | LTS + npm 5 + async_hooks |
| 10.x | 2018-04 | HTTP/2、n-api 稳定 |
| 12.x | 2019-04 | V8 升级、ES Modules 试验 |
| 14.x | 2020-04 | 首次原生支持 ES Modules、V8 8.1 |
| 16.x | 2021-04 | V8 9.0、fs/promises 稳定 |
| 18.x | 2022-04 | 内置 fetch、test runner |
| 20.x | 2023-04 | 权限模型、Single Executable Applications |
| 22.x | 2024-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:
之后进项目就 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 内置模块(fs、path、process)和环境变量:
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
|
这种"半自动"流程的痛点:
- 任何一步失败要人工介入
- 镜像 tag 写死在 yaml 里,回滚要 git history
- 没有镜像扫描、签名、版本元数据
改进方向:把这条脚本拆成 GitLab CI / Jenkins Pipeline 的 stage,加 docker scan(trivy)、Helm Chart 管理版本。
小结
Node 装包是前端所有事的"前置依赖"。本文核心要点:
- 生产用 LTS(写作时是 Node 20/22),绝不用奇数版
- 多版本用 NVM(Linux/macOS)或 nvm-windows(Windows),
.nvmrc 锁版本 - 国内必设镜像:
registry.npmmirror.com 或 cnpm - npm 全局路径自定义,避免污染 C 盘或系统目录
- 物理机打包流程是"从 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.6、npm 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 LTS | Bun 1.x | Deno 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 v3:
package-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 5 | Runes 语法(编译时反应性)+ 体积 -30% |
| Solid.js 1.9 | 2024 性能 SOTA |
| Astro 5 | 内容驱动 + Island 架构 |
| Next.js 15 | React 19 + Turbopack GA |
| Nuxt 3.14 | Vue 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(轻量框架)
|