ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Windows下用nvm-windows管理Node多版本与npm配置指南

Windows下用nvm-windows管理Node多版本与npm配置指南 Windows 上搭 Node 环境说简单也简单官网下个安装包一路下一步就完事说麻烦也是真麻烦——等你手上同时压着三个项目分别跑在 Node 18、20、22 上其中一个还依赖只能在特定版本里编译通过的 native 模块你就会开始怀念那种一行命令切版本的爽快。这篇内容就是把我这几年在 window系统 上来回重装、反复踩坑的经验摊开讲清楚nvm 的安装与卸载、node 的安装与卸载、版本切换、npm 全局安装目录那一堆绕人的路径问题、镜像源怎么配以及那几种一看就头大但修起来只要两分钟的报错。不管你是刚拿到新电脑准备配环境的新手还是带了小团队要统一开发环境的老兵都建议按顺序看一遍尤其是第二章和第五章这两块是我见过翻车率最高的地方。1. 为什么 Windows 上要折腾 nvm而不是直接装官方包1.1 三个真实场景逼着你必须用版本管理器先说结论单版本开发用不着 nvm多版本共存就绕不开它。我遇到的第一类场景是老项目维护某个 2020 年前后起的后台管理系统锁死在 Node 14 的语法和依赖树上升级 Node 就等于重做一遍构建链。第二类是 native 模块编译某些依赖需要本地编译工具链Node 主版本一换ABI 版本号就变缓存下来的二进制直接失效报错信息还很含糊。第三类是尝鲜新框架要求 Node 20 以上你要是全局只有 14就只能来回卸载重装一次十几分钟一天下来什么都别干了。这背后的原理其实不复杂。Node 的每次主版本升级都伴随 V8 引擎和内置模块 API 的变化而 npm 包里那些带.node后缀的二进制文件是按 ABI 版本预编译的ABI 对不上就只能现场重新编译。nvm 解决的就是把整套 Node 运行时变成可插拔的目录切换时只改一个符号链接的指向项目侧完全无感。1.2 nvm-windows 和 macOS/Linux 上的 nvm 不是同一套东西这是最容易踩的认知坑。macOS 和 Linux 上大家说的 nvm 是 shell 脚本实现靠修改当前终端的 PATH 环境变量来切版本而 window系统 上用的是nvm-windows它是用 Go 写的独立可执行程序靠创建一个叫nodejs的目录符号链接指向具体的版本目录来实现切换。这个差别带来三个实际后果你一定要提前知道切换版本必须动符号链接所以默认需要管理员权限或者开启开发者模式。每个 Node 版本下面的全局 npm 包是各自独立的切到新版本后之前装的全局 CLI 全都不见了。环境变量里只能有一条 Node 路径也就是那个符号链接目录别自己再手动加别的。我见过有同事照着 macOS 的教程在 Windows 上敲nvm alias default 18结果提示找不到命令就是因为两套工具的命令集压根不重叠。nvm-windows 用得最多的命令其实就六七个后面第三章会逐个讲。1.3 动手之前先把旧的 Node 环境清理干净这一步偷懒的话后面一定会出怪问题比如nvm use成功但node -v还是老版本号或者 npm 全局命令指向了一个不存在的目录。原始安装包装的 Node 会留下这些东西建议逐个确认并删除需要清理的对象常见位置不清理的后果Node 安装目录C:\Program Files\nodejs与 nvm 的符号链接目录冲突切换失败npm 全局包目录C:\Users\你的用户名\AppData\Roaming\npm旧全局命令残留和 nvm 的目录打架系统 PATH 条目系统属性里的环境变量老路径优先级更高命令指向错误的 nodenpm 缓存C:\Users\你的用户名\AppData\Local\npm-cache可选空间紧张时再删nvm 旧版本C:\Users\你的用户名\AppData\Roaming\nvm残留配置导致新装版本读错镜像地址操作顺序建议是先通过设置 - 应用卸载 Node然后手动删掉上面那两个目录如果卸载没删干净最后去环境变量里把 PATH 中所有跟 node、npm 相关的条目删掉。删完一定要重新打开一个终端因为环境变量是进程启动时读取的老终端里还是旧值会让你误以为没删干净。验证方式很简单新开一个 cmd 敲node -v如果提示不是内部或外部命令说明清理干净了可以进入下一步。2. nvm-windows 完整安装流程与参数选择2.1 下载渠道与安装目录规划认准coreybutler/nvm-windows这个项目在 Releases 页面下载nvm-setup.exe。别去各种下载站找中文版nvm-windows 本身就是单文件安装器没有汉化版第三方打包的版本有夹带风险。目前稳定版是 1.1.x 系列安装器是向导式的但有两个目录会让你选这两个选择很关键NVM 安装目录默认在C:\Users\你的用户名\AppData\Roaming\nvm。我一般改成D:\dev\nvm理由是放在用户目录下某些清理软件会把它当成缓存删掉而且路径带空格和中文名时偶发问题。路径不要有空格、不要有中文这条是硬性要求。Node 符号链接目录默认是C:\Program Files\nodejs。这个目录不用你手动建nvm 会自己管。如果你的公司电脑对Program Files有写入限制可以改到D:\dev\nodejs但改完要确保这个路径被加进了系统 PATH。顺便说一句如果你的项目放在机械硬盘而 nvm 装在固态上不用担心符号链接只是个指路牌实际文件还是跟着 nvm 目录走所以把 nvm 装在读写最快的盘上装包和编译速度会有肉眼可见的差别。2.2 settings.txt 里到底配了什么安装完成后打开 nvm 安装目录下的settings.txt你会看到类似这样的内容root: D:\dev\nvm path: C:\Program Files\nodejs node_mirror: https://npmmirror.com/mirrors/node/ npm_mirror: https://npmmirror.com/mirrors/npm/ proxy: noneroot是各版本 Node 的实际存放地path就是那个符号链接目录。node_mirror和npm_mirror默认是官方源国内环境下下载一个 Node 包可能要几分钟甚至直接超时改成上面的国内镜像后会快非常多实测从十几分钟降到一两分钟。这个配置必须在第一次nvm install之前改好已经下了一半的包改配置不会自动重下得先清掉root目录下对应的半成品文件夹。proxy这一项留none就行。如果你的网络环境需要走公司内网代理才能访问外网这里可以填代理地址格式是http://主机:端口改完同样要重开终端。还有个小细节这个文件里不要随意加空行和注释某些版本解析配置比较严格多一行注释就可能导致读取失败表现为nvm install时提示无法解析配置。2.3 验证安装三条命令确认环境正确装完之后以管理员身份打开一个新的 PowerShell 或 cmd依次执行nvm version # 输出版本号例如 1.1.12 nvm root # 输出 NVM 安装目录核对是否和你选的一致 nvm list available # 列出可安装的版本能列出来说明镜像可达nvm list available这一步很重要它同时验证了三件事程序本身能跑、配置文件能被解析、镜像地址网络可达。如果这一步卡住不动八成是镜像地址写错了或者被公司网络策略拦了。三条都通过说明 nvm 层面已经没有问题。提示nvm version输出里如果带一串疑问号或者乱码通常是终端编码问题执行chcp 65001切到 UTF-8 就好不影响功能。2.4 卸载 nvm 本身怎么卸干净换电脑、换开发环境或者纯粹想推倒重来的时候nvm 的卸载比安装更需要小心因为它留下了环境变量和符号链接。正确顺序是先用nvm uninstall把所有已安装的 Node 版本逐个卸掉可选但能省下几个 G 空间。到 nvm 安装目录运行卸载程序unins000.exe或者在设置 - 应用里找到 NVM for Windows 卸载。手动检查并删除残留目录nvm 根目录、Node 符号链接目录卸载器一般会删但符号链接有时会变成空壳。打开环境变量面板把NVM_HOME、NVM_SYMLINK两个变量删掉并从 PATH 中移除对应的两条记录。重开终端敲nvm和node都应该提示命令不存在。第 4 步是重灾区。很多人只跑了卸载器环境变量还留着结果新装一遍 nvm 时安装器检测到旧变量就直接复用路径对不上就出现nvm 能运行但找不到任何 Node 版本的诡异现象。删环境变量不费事但能省你半小时排查时间。3. Node 的安装、切换与彻底卸载3.1 安装指定版本与权限那点事装版本的命令就一句但前后的门道不少nvm install 22.19.0 # 安装指定版本 nvm install 20.18.1 # 再装一个 LTS方便切换 nvm list # 查看已安装的所有版本 nvm use 22.19.0 # 切换当前使用的版本 node -v # 验证输出 v22.19.0 npm -v # 验证 npm 是否同步可用关于版本选择我的建议是主力版本选当前 LTS22.x 系列老项目维护再按需装 18.x 或 20.x。18.x 已经进入维护末期新项目不要再选它。安装时如果只写nvm install 22nvm-windows 会自动挑 22 系列里最新的一个这个行为在个人开发机上是方便的但在团队里不推荐因为不同时间点安装可能拿到不同的补丁版本容易出现我这能跑你那不行。nvm use这一步是权限问题的集中爆发点。它的本质是删除旧的符号链接再建一个新的而创建符号链接在 Windows 上默认需要管理员权限。三种解决方式按推荐度排序打开设置 - 系统 - 开发者选项启用开发人员模式之后普通权限的终端也能建符号链接。这是我最推荐的做法一次设置长期受益。每次切换都用管理员终端。麻烦但绝对稳。把符号链接目录设成当前用户有完全控制权的路径比如D:\dev\nodejs配合开发人员模式基本不会再报权限错。如果看到exit status 1: Access is denied或者提示需要提升权限就是这个问题不用怀疑是 nvm 坏了。3.2 多版本共存与项目级版本锁定nvm list的输出里当前正在使用的版本前面会有个星号或者箭头标记看这个就能确认切换是否生效。多版本共存本身没什么技术含量真正麻烦的是让项目自动用对版本。macOS 上的 nvm 会自动读项目根目录的.nvmrc文件nvm-windows 不支持这个特性这是个实打实的短板。折中方案有两个一是在项目 README 里明确写清楚版本号配合package.json的engines字段做软性约束{ engines: { node: 20.0.0 23.0.0, npm: 9.0.0 } }engines默认只是警告不会阻止安装想让它变成硬性拦截需要在项目里加.npmrc并写入engine-stricttrue。这招在多人协作里很有效能挡住本地版本不对还硬装依赖的情况。另一个方案是写个两行的批处理脚本放在项目根目录内容是nvm use 20.18.1 npm run dev让所有人都用这个脚本启动。土是土了点但零学习成本新人拉下代码就能跑。我在几个小团队里推过这个做法比要求所有人背版本号靠谱得多。3.3 卸载某个 Node 版本与残留清理卸载单个版本很简单nvm uninstall 18.20.2有两条限制要注意。第一不能卸载当前正在使用的版本必须先nvm use切到别的版本再卸否则会提示版本正在使用中。第二卸载不会自动清理这个版本下你装过的全局包实际上整个版本目录会被删掉所以全局包自然也没了这一点你心里要有数如果那个版本里装着某个你常用的 CLI 工具卸完记得在新版本里重装一遍。如果卸载过程中报目录被占用或者删不干净通常是还有 node 进程在跑。检查方法是打开任务管理器搜node.exe全部结束掉如果用的是编辑器内置终端把编辑器整个关掉再试。Windows 上文件句柄释放比 Linux 慢实在不行重启一次比反复重试省时间。3.4 版本切换后必做的三件事每次切完版本我会习惯性做三个检查这三条能挡掉大部分切了版本但行为没变的怪问题node -v和npm -v都要看。有时候 node 切成功了但 npm 还是旧版本目录里的原因是 PATH 顺序问题重开终端一般能解决。npm ls -g --depth0看一眼全局包列表。你会发现切版本之后全局包全空了这是 nvm-windows 的设计使然不是故障。项目目录下如果有node_modules建议删掉重装。因为里面可能含有按旧 ABI 编译的二进制文件不删的话运行时报的是很隐晦的模块加载错误排查起来特别费劲。4. npm 全局安装目录、镜像与常见工具4.1 npm 从哪来和 node 是什么关系npm 不是独立安装的它跟着 Node 一起来。nvm install 22.19.0完成后这个版本目录下就自带了一个 npm。所以你永远不需要单独去安装 npm网上那些 npm 安装教程大多是老版本的遗留思路。需要单独操作的情况只有一种升级 npm 本身。因为自带的 npm 版本通常比最新版落后一两个小版本某些新特性用不了这时执行npm install -g npmlatest这里必须提醒一句npm 是全局装的也就是装在你当前这个 Node 版本下面。切到另一个版本npm 又回到自带的旧版本了。所以升级 npm 这个动作每切到一个新版本都要做一次或者干脆接受自带版本反正绝大多数场景够用。4.2 全局安装目录到底在哪PATH 怎么对上这是新手最容易懵的地方npm install -g xxx装完命令敲不出来。根本原因是全局 bin 目录没在 PATH 里或者 PATH 里有但指向了别的版本。先查清楚目录在哪npm config get prefix在 nvm-windows 环境下输出类似D:\dev\nvm\v22.19.0。注意这个路径带版本号这就是为什么全局包不跨版本共享。全局包本体在prefix\node_modules可执行文件的入口脚本直接放在prefix下面。然后确认 PATH 里有没有这个目录。有意思的是你不需要为每个版本单独加 PATH——因为 nvm 的符号链接目录比如C:\Program Files\nodejs本身就在 PATH 里而 npm 会把全局 bin 映射到符号链接目录下。前提是切换版本时用的是nvm use而不是手动改 PATH。一旦你手动往 PATH 里塞了某个具体版本目录就会出现切版本后命令还在的混乱状态这个坑我踩过后来花了一个下午才理清。如果你想让全局包在不同 Node 版本间共享可以改npm config set prefix D:\dev\npm-global然后把D:\dev\npm-global加进 PATH。这么做的好处是全局 CLI 只装一份代价是某些对 Node 版本敏感的包比如带 native 依赖的可能在切换后报错。我个人的选择是不共享宁可多装几次换来的是每个版本环境干净独立出问题好定位。4.3 镜像源配置一次配好长期省心国内环境下不换镜像源装包体验会很差。推荐直接改用户级配置一次生效所有项目npm config set registry https://registry.npmmirror.com npm config get registry # 验证如果只想给单个项目配置就在项目根目录建一个.npmrc文件registryhttps://registry.npmmirror.com engine-stricttrue用户级配置文件在C:\Users\你的用户名\.npmrc项目级的会覆盖用户级。除了 registry还有几个配置值得一起设上strict-ssl保持默认 true 不要关关了等于放弃校验fetch-timeout可以适当调大比如 120000网络抖动时能少失败几次。注意换镜像源只影响包的下载地址不影响包的完整性和版本号。但如果某个包在镜像上同步延迟可能出现官方有新版、镜像还没同步的情况这时候npm view 包名 versions看到的结果会不一样别误判成自己环境坏了。4.4 全局装 pnpm、yarn 和常用 CLI 的正确姿势全局安装命令本身没有难度npm install -g pnpm npm install -g yarn npm install -g vue/cli pnpm -v真正需要注意的是顺序和验证。装完之后先where pnpmPowerShell 里用Get-Command pnpm确认路径落在 nvm 的目录下。如果路径指向了C:\Users\xxx\AppData\Roaming\npm说明你还有旧的 npm 全局目录残留在 PATH 里而且它的优先级更高这时候两个目录的包会互相干扰表现为明明装了但版本不对。另外提一句 pnpm 的一个特性它默认把包存到全局 store然后通过硬链接共享到各项目。这个机制在切换 Node 版本后理论上 store 里的内容可以复用但如果遇到诡异的模块解析错误可以试试pnpm store prune清一下缓存成本很低成功率不低。5. 高频报错排查速查表5.1 npm.ps1 禁止运行脚本出现频率第一名报错长这样npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1因为在此系统上禁止运行脚本。这不是 nvm 或 npm 的问题是 PowerShell 的执行策略默认太严。# 查看当前策略 Get-ExecutionPolicy -List # 只对当前用户放行推荐不需要管理员 Set-ExecutionPolicy -Scope CurrentUser RemoteSigned改完重开终端即可。RemoteSigned的含义是本地脚本随便跑从网上下载的脚本需要签名这个级别在个人开发机上是安全的不要图省事设成Unrestricted。如果你不想动执行策略最简单的方法是用 cmd 代替 PowerShellcmd 没有这层限制。顺便说一个变体报错路径是D:\node\npm.ps1或者别的盘说明你还留着旧环境的残留按第一章 1.3 节的方法清理 PATH 就行。5.2 npm 不是内部或外部命令Path 出问题了这个报错的排查路径很固定按顺序走nvm list看是否有已安装版本、是否有星号标记当前版本。如果没有星号说明没执行过nvm use执行一次即可。如果有星号但命令还是找不到打开环境变量看 PATH 里有没有 nvm 的符号链接目录以及它有没有排在旧路径前面。符号链接目录存在但里面是空的说明链接坏了重新执行nvm use修复。我遇到过最隐蔽的一次是符号链接目录看起来正常但实际指向了一个已经被删掉的版本因为卸载版本时没先切走链接成了死链。这种情况下node -v会报错修复方式就是随便nvm use一个存在的版本。5.3 EPERM、EBUSY 与文件占用npm err! code EPERM和npm err! code EBUSY基本都是一个原因你要删或改的文件正被别的进程占用。典型触发场景有四个报错触发原因处理方式EPERM operation not permitted杀毒软件实时扫描锁文件把 nvm 目录和项目目录加入杀软白名单EBUSY resource busy编辑器或终端正在使用 node_modules关掉所有终端、编辑器后重试EPERM unlink切换版本时还有 node 进程任务管理器结束所有 node.exeENOTEMPTY目录被索引服务扫描中等几秒重试或关闭 Windows 搜索索引如果这些都不奏效还有一招万能方案把整个node_modules目录删掉重装。删都删不掉的话用管理员 cmd 执行rd /s /q node_modules比在资源管理器里删靠谱得多。5.4 模块加载与原生依赖类报错cannot find module node:path、the requested module node:util does not provide an export named、cannot find native binding这三类报错经常被误认为是环境装坏了其实多数跟版本不匹配有关。node:path、node:util这种带node:前缀的写法是 Node 14.18 之后才稳定支持的语法。如果你的项目代码或者某个依赖用了这种写法而当前跑的是个很老的 Node就会报找不到模块。解决办法就是切到 18 以上版本别在老版本上硬撑。cannot find native binding通常跟 optional dependencies 和缓存有关。npm 在某些情况下会漏装平台相关的可选依赖或者从旧版本切过来时缓存的二进制不匹配。标准处理流程是三步删掉node_modules和package-lock.json执行npm cache clean --force然后重新npm install。这套组合拳我用了不下二十次成功率在九成以上。5.5 网络与镜像相关报错request aborted、ETIMEDOUT、ECONNRESET这类基本就是网络问题。先确认镜像源是否生效npm config get registry再确认是不是只有某一个大包失败——如果是多半是那个包体积大加上网络抖动重试两三次通常能过。可以设置重试次数npm config set fetch-retries 5 npm config set fetch-retry-maxtimeout 120000还有一种情况是公司网络有拦截策略表现为所有请求都超时但浏览器能上网。这时候需要找网络管理员确认或者使用公司内部的私有仓库地址。别在这里浪费时间反复试网络层面的限制本地怎么调都没用。6. 长期维护与团队协作中的几个经验6.1 目录规划一次定好三年不折腾我现在的目录结构是这样的nvm 装D:\dev\nvm符号链接目录用默认的C:\Program Files\nodejs项目代码放D:\code。原则就三条不带空格、不带中文、跟系统盘分离。前两条是避免各种诡异的路径解析问题第三条是为了重装系统时不用重新下载几十个 G 的依赖。有条件的话把 nvm 和代码都放固态盘npm install和构建速度提升很明显。还有一个小习惯每装一个新 Node 版本顺手跑一遍npm config set registry ...和npm install -g pnpm。因为全局配置和全局包都是跟着版本走的不补的话下次切过去又要重新想起来。6.2 把环境要求写进项目文档而不是口头传递团队协作里最浪费时间的对话就是我这能跑啊。我的做法是在 README 顶部放一个环境表项目要求说明Node20.18.1精确到补丁版本避免构建差异包管理器pnpm 9.x统一用 pnpm禁用 npm install安装命令pnpm install不允许用 npm锁文件会冲突精确到补丁版本看起来有点过分但真的能省掉很多本地构建产物和 CI 不一致的排查。配套在package.json里写好engines和packageManager字段现代包管理器会自动读取并给出提示比人肉提醒有效得多。6.3 迁移和备份换电脑时怎么最快恢复换了新电脑恢复开发环境我有固定的四步装 nvm、改settings.txt的镜像地址、nvm install上三个常用版本、在每个版本里补装全局 CLI。整个过程二十分钟以内搞定。值得单独备份的是用户级的.npmrc文件里面往往攒了多年配置私有仓库地址、代理、超时参数等拷过来能省不少事。项目级的锁文件更要进版本控制package-lock.json或pnpm-lock.yaml是保证依赖一致性的关键千万别写进.gitignore。最后分享一个我最近养成的小习惯在项目根目录放一个setup.md只用五行写清楚用什么版本、怎么装依赖、怎么启动新同事照着做基本不会出错。花五分钟写能省掉后续无数次重复解答。这个环境配置套路还能往两个方向扩展一是把 Node 环境纳入容器或虚拟化方案让本地完全不用管版本二是用corepack管理包管理器版本让packageManager字段真正生效。这两个方向我都试过各有各的适用边界等你的项目规模上来之后再考虑也不迟。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进