用了这么多年 npm,我最深的感受是:这工具平时看着简单,无非就是npm install、npm run build,可一旦环境出问题,报错能让人折腾一整天。比如npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本,又比如ERESOLVE overriding peer dependency、EBUSY、npm ERR! code EUNSUPPORTEDPROTOCOL,每一个都是新手劝退现场。
这篇不是说明书式的罗列,而是把我这些年实际用过的 npm 常用命令、踩过的坑、以及排查思路按场景拆开讲清楚。从环境配置、镜像源、项目初始化、依赖安装,到脚本运行、包发布、报错排查,基本覆盖日常开发和发布流程里能碰到的高频操作。不管你是刚接触 Node.js 的新人,还是被各种疑难杂症折磨过的老手,这份清单都值得先收藏再往下看。
1. 环境配置与镜像源:装好之后先做这三件事
1.1 先分清 npm、Node.js、npx 的区别
很多人一上来就敲命令,遇到报错不知道怎么查,其实是没分清这几个东西。Node.js 是一个 JavaScript 运行环境,你的 JS 代码最终靠它跑起来;npm 是随 Node.js 一起安装的包管理器,负责下载、安装、卸载第三方依赖,你可以把它理解成一个“应用商店”;npx 则是 npm 5.2 之后附带的一个工具,专门用来直接执行某些包的命令,而不需要先把包装到项目里。
这个概念为什么重要?因为你会发现很多报错其实是概念混了导致的。比如有人问我“为什么我全局安装了某个库,项目里还是提示找不到”,大概率是把全局安装和局部安装的作用域搞混了,后面我会专门讲-g的问题。
顺带说一句,网上搜 npm 相关问题的时候,经常会把 linux 常用命令、git 常用命令混在一起推荐给你。那些内容不是没用,但和 npm 本身无关。你只需要记住,npm 所有的行为都围绕“当前项目目录”和“全局环境”两个维度展开,绝大部分问题都能归到这两类里。
1.2 查看版本、目录与当前配置:npm -v / npm config list / npm root -g
环境装好之后,我建议先跑一组命令确认基础状态。这一组命令不需要全背,但一定要知道它们是干什么的,排查问题时能救命。
node -v npm -v npm config list npm config get registry npm root -gnode -v和npm -v用来确认版本,如果提示“无法将‘npm’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”,说明 Node.js 没有正确安装,或者环境变量 PATH 没配上,终端里看不到 npm 所在的目录。这种情况通常重装 Node.js LTS 版本、勾选“Add to PATH”就能解决,装完记得重启终端。
npm config list会输出当前的 npm 配置,包括 registry、proxy、cache 目录、prefix 等等。我排查问题的时候第一步就是看这个,因为很多奇怪的网络报错,根因是配置被改过。npm root -g用来查看全局安装包的位置,配合npm config get prefix可以确认全局目录到底在哪。
顺手整理张速查表:
| 命令 | 作用 | 常见使用场景 |
|---|---|---|
node -v | 查看 Node.js 版本 | 确认环境是否正常 |
npm -v | 查看 npm 版本 | 确认 npm 是否可执行 |
npm config list | 查看所有配置 | 排查 registry、proxy 等问题 |
npm config get registry | 查看当前镜像源 | 判断是否使用了自定义源 |
npm root -g | 查看全局包安装目录 | 配合 PATH 排查命令找不到的问题 |
npm config get cache | 查看 npm 缓存目录 | 手动清理缓存时使用 |
1.3 国内镜像源配置与切换:npm config set registry
npm 默认的官方源在国外,网络不稳定的时候,装个依赖能卡到怀疑人生。所以很多团队和个人会配置国内镜像源,最常用的就是 npmmirror,也就是原来的淘宝 npm 镜像。
配置方式很简单:
npm config set registry https://registry.npmmirror.com设置之后用npm config get registry验证,看到输出的地址变成你设置的值就说明生效了。如果想恢复官方源,执行:
npm config set registry https://registry.npmjs.org/注意,npm 的配置是有层级的。npm config set默认改的是用户级配置,也就是当前登录用户生效;但如果你在项目目录下创建了一个.npmrc文件,那么项目内执行的命令会优先读取这个文件里的配置。所以有时候大家会遇到“我明明改了镜像源,为什么这个项目还是走官方源”的问题,先检查项目根目录下有没有.npmrc。
如果你需要在多个源之间来回切换,我建议直接装一个nrm工具:
npm install -g nrm nrm ls nrm use taobaonrm ls会列出当前可用的镜像源列表,nrm use taobao一键切换到淘宝镜像。它的本质还是修改 npm 的 registry 配置,但比手动敲命令方便很多。
这里要提醒一句:如果你的公司有私有 npm 仓库,比如上传了内部组件包的仓库,那镜像源务必要指向公司地址,别用公共镜像。否则npm publish会把包传到公共仓库,造成事故。我见过有人把 registry 全局改成淘宝源之后,直接npm publish,结果包被发布到了公共镜像上,处理起来非常麻烦。
1.4 解决 PowerShell 禁止运行脚本:npm.ps1 报错
Windows 上非常高频的一个报错是:
npm : 无法加载文件 C:\Program Files\nodejs\npm.ps1,因为在此系统上禁止运行脚本。一看就很吓人,其实原因非常简单:Windows 的 PowerShell 默认执行策略是 Restricted,禁止运行任何.ps1脚本。而 npm 在 PowerShell 下会调用npm.ps1,于是被拦下来了。
解决办法有几种,我推荐用官方推荐的“当前用户级别”策略修改:
- 以管理员身份打开 PowerShell。
- 执行下面的命令:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser - 输入
Y确认,然后重新打开 PowerShell,再执行npm -v验证。
为什么用RemoteSigned而不是Unrestricted?RemoteSigned的意思是:本地创建的脚本可以运行,从网络下载的脚本必须有可信签名才能运行。这个策略比完全放开更安全,能满足日常开发需求,又不会让系统裸奔。
如果你不想改执行策略,也有两个替代方案:一是直接用cmd命令行窗口执行 npm 命令,二是每次用npm.cmd代替npm,比如npm.cmd -v。但说实话,改执行策略是治本,后面用 PowerShell 做前端开发会顺很多。
还有人会遇到另一种报错:“无法将‘npm’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”。这个更像 PATH 配置问题,去系统环境变量里确认 Node.js 的安装目录在不在 Path 里,重新安装 Node.js 的时候注意勾选自动配置 PATH 即可。
2. 初始化项目与依赖安装:npm init / install / ci / uninstall 全套
2.1 npm init 与 package.json 的诞生
不管你是创建前端项目还是 Node.js 后端项目,第一步基本都是初始化package.json。执行npm init会进入交互式问答,问你项目名、版本、描述、入口文件、作者、license 等等。如果不想一段段答,直接加-y参数:
npm init -y这样会生成一个带默认值的package.json。不过默认值里的main字段通常是index.js,scripts字段是空的,实际项目里往往还要手动调整。
我自己的习惯是,在npm init -y之后立刻做两件事:第一,把"private": true加上,防止哪天不小心把项目发布到 npm 上;第二,把常用的脚本先预填到scripts字段里,比如:
{ "name": "my-project", "version": "1.0.0", "private": true, "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" } }除了手动改文件,新版 npm 还支持用命令直接设置字段,比如:
npm pkg set scripts.dev="vite" npm pkg set private=true这样不用打开编辑器就能改package.json,在某些自动化脚本里很好用。
2.2 npm install 的参数:-g / -D / --save-prod / --no-save / --legacy-peer-deps
npm install是使用频率最高的命令,但很多人只学会了默认安装,实际上它有好几个核心参数需要区分清楚。
默认执行npm install <package>会把包装包写入dependencies,这是生产环境依赖。如果是开发阶段的工具链、测试框架之类的,应该装到devDependencies:
npm install <package> -D-D是--save-dev的简写。对应还有--save-prod或-P,作用是显式写入dependencies。如果只是临时想装个包试一试,不想写进package.json:
npm install <package> --no-save全局安装参数是-g:
npm install -g <package>全局安装的包会被放到前面提到的npm root -g目录下,可以在任何终端直接执行其命令。但要注意,很多 CLI 工具并不适合全局安装,因为不同的项目可能需要不同版本,全局安装容易造成版本冲突。我现在的习惯是:能用npx替代的就不用全局安装,比如create-vite、eslint、prettier这些,本地安装加npx更可控。
还有一个高频参数是--registry,可以临时指定镜像源:
npm install <package> --registry=https://registry.npmmirror.com这个适合偶尔安装某个大包时不想改全局配置的场景。
如果遇到依赖冲突,npm 7 之后会严格校验peerDependencies,可能提示ERESOLVE overriding peer dependency。很多人会用--legacy-peer-deps跳过检查:
npm install --legacy-peer-deps这个参数会让 npm 采用老版本的依赖解析逻辑,绕过 peer 冲突。它能解决眼前的问题,但可能掩盖真实的版本冲突,所以最好的做法还是手动调整依赖版本,实在没办法再考虑用它。
2.3 npm ci 与 npm install 到底怎么选
npm ci是 CI/CD 环境下非常推荐使用的命令,它和npm install有本质区别。
npm ci必须基于package-lock.json,安装时会先删除node_modules,然后严格按照 lockfile 中锁定的版本重新安装。整个过程更干净、可复现,速度也通常更快,因为它不会对依赖树做额外的分析解析。缺点是,如果package-lock.json和package.json不一致,它会直接报错,不会自动修复。
npm install则灵活得多,它会根据package.json里的版本范围去解析最新兼容版本,并且可能更新package-lock.json。所以在本地开发时,你执行npm install后 lockfile 可能会变化,这是正常现象。
我给的选型建议很直接:
| 场景 | 推荐命令 | 原因 |
|---|---|---|
| 本地第一次拉代码装依赖 | npm install | 允许更新 lockfile,兼容不同 Node 版本 |
| CI/CD 流水线构建 | npm ci | 精确复现 lockfile,避免意外升级 |
| 线上发布前构建 | npm ci | 保证每次构建依赖完全一致 |
| 本地删除后重新安装 | npm ci | 干净、快速,不受旧残留影响 |
有个小技巧,如果本地想模拟 CI 的干净环境,也可以直接先删掉node_modules再npm ci。但不要轻易手动删node_modules,Windows 下会遇到文件占用问题,我后面会讲。
2.4 卸载、清理与重建依赖:uninstall / prune / dedupe
卸载依赖的命令是npm uninstall <package>。可以简写成npm rm <package>,作用是一样的。它会从node_modules中移除包,同时自动更新package.json和package-lock.json。
全局卸载写法:
npm uninstall -g <package>这个要特别小心,很多人全局装了 CLI 工具之后想卸载,结果忘了加-g,在项目目录里执行,发现项目依赖没变,工具也还在。所以每次卸载前先确认你到底是想卸全局还是局部。
npm prune是一个经常被忽视的命令,它的作用是删除node_modules里那些没有出现在package.json中的多余依赖。运行完npm prune之后,依赖树会变得清爽。配合环境变量还可以清理开发依赖:
npm prune --production这个命令会移除devDependencies,适合在只跑生产环境代码的服务器上缩小 node_modules 体积。
npm dedupe则是减少依赖重复的。npm 在安装依赖时,如果多个包都依赖同一个版本的库,理论上可以提升到顶层共享。但有些情况下由于版本冲突,同一个库可能被安装了多份到不同层级,npm dedupe会尽量重新整理,让依赖结构更扁平化。一般项目不需要经常运行它,但如果发现node_modules特别臃肿,可以试试。
2.5 本地调试 npm 包:npm link 与 npm pack
自己开发 npm 包时,最头疼的问题是“还没发布,怎么在当前项目里试”?两个常用方案:npm link和npm pack。
npm link的思路是软链接。在包目录下执行:
npm link这会把当前包链接到全局的 node_modules 下,生成一个软链。然后在你需要使用的项目目录里执行:
npm link <package-name>这样项目里的node_modules/<package-name>就指向你本地正在开发的包目录,改代码即时生效,非常适合开发调试。
调试完之后要解除链接:
npm unlink <package-name>这个命令会移除项目里的链接,但可能不会自动删除全局链接,如果确认不再需要,可以再执行一次npm rm --global <package-name>把全局链接清理掉。
另一个方案是npm pack,它会将当前目录打包成一个.tgz文件,模拟发布时的产物。你可以先执行:
npm pack --dry-run查看打包会包含哪些文件,确认无误后执行npm pack,得到一个xxx-1.0.0.tgz。然后在目标项目里:
npm install /path/to/xxx-1.0.0.tgz这个方式能更真实地模拟发布后的安装过程,适合检查包内容是否完整。我发布包之前一定会先跑一遍npm pack --dry-run,看看有没有把不该发布的文件带进去。
3. 脚本运行、依赖检查与升级:run / exec / list / outdated / update
3.1 npm run 的秘密:pre/post 钩子与参数传递
npm run是项目开发的核心入口。比如前端项目里常见的npm run dev、npm run build、npm run serve,本质上执行的都是package.json中scripts字段里定义的命令。
关键点在于,npm 在执行脚本时会把node_modules/.bin临时加入 PATH。这意味着,你在 scripts 里可以直接调用项目本地安装的命令行工具,不用写完整路径。比如:
{ "scripts": { "build": "vite build" } }就算你没有全局安装 vite,只要项目里装了 vite,执行npm run build就能跑起来。
npm run后面还可以传参数。执行npm run dev -- --host,实际运行的命令是dev -- --host?不对,实际上是npm run dev会把--host追加到原始命令后面,所以要写npm run dev -- --host,也就是多一个--,用来分隔 npm 自身参数和你要传给脚本的参数。比如 Vite 项目想监听局域网地址:
npm run dev -- --host 0.0.0.0这个命令会变成vite dev --host 0.0.0.0。很多初学者漏了--,结果参数传不进去,白白浪费时间。
还有 pre/post 钩子。比如你定义了prebuild、build、postbuild三个脚本,执行npm run build时,npm 会自动先执行prebuild,再执行build,最后执行postbuild。这个特性很适合在构建前做 lint、构建后做部署通知等操作。
3.2 npm exec 与 npx:不用安装就能执行命令
npx是让很多人眼前一亮的功能。它最大的价值不是帮你下载包,而是可以直接执行某个包的命令,还不用把它写进项目依赖。
最常见的是:
npx create-vite my-app这条命令会临时下载create-vite,执行完脚手架创建,然后不会污染你的项目依赖,也不需要全局安装。它的查找顺序是:先找项目本地node_modules/.bin,找不到再找全局,最后才临时下载。
新版 npm 还提供了npm exec,功能和 npx 基本一致。比如:
npm exec --package=lodash -- node -e "const _ = require('lodash'); console.log(_.chunk([1,2,3,4], 2))"这个用法适合在不需要包常驻依赖的情况下,临时用某个库跑一段脚本。不过日常使用中,npx的语法更简洁,我还是推荐多用npx。
这里有个容易踩坑的点:如果你在本地项目里装了某工具,但版本和你npx临时拉取的最新版不一样,行为可能不同。所以 CI 脚本里尽量不要用npx去拉不确定版本的包,最好还是通过npm ci安装固定版本,再用本地命令执行。
3.3 依赖体检:npm list / outdated / update / why
项目依赖多了之后,经常要回答几个问题:这个包装了吗?版本是多少?是不是太旧了?为什么会被装进来?
npm list用来查看依赖树。最常用的是只显示顶层依赖:
npm list --depth=0或者查看全局包:
npm list -g --depth=0如果某个包报错说找不到,也可以用npm list <package>检查它是否真的存在。
npm outdated会列出现在安装的版本、package.json 要求的版本区间,以及最新的版本号。三列分别叫 Current、Wanted、Latest。Wanted 是符合 package.json 版本范围的最新版本,Latest 是发布出来的最新版本。npm update默认只会把依赖更新到 Wanted,不会直接跳到 Latest,这其实是个安全设计,避免引入破坏性更新。
如果想精确更新某个包到最新大版本,用:
npm install <package>@latest还有一个npm why或npm explain命令,可以查看某个包为什么会在依赖树里。比如你用npm list发现项目里多了一个自己没安装过的包,可以执行:
npm explain <package>它会显示出是哪个顶层依赖把它带进来的。排查幽灵依赖或者重复依赖的时候,这个命令非常有用。
3.4 package-lock.json 和依赖锁定策略
package-lock.json的重要性再怎么强调都不过分。它记录了项目里每一条依赖的具体版本、下载地址、依赖关系和哈希值,是保证“每个人安装结果一致”的关键。
用npm install安装新包或修改package.json后,lockfile 会自动更新。这个文件一定要提交到 Git 仓库里,不能加到.gitignore。否则团队成员各自执行npm install,可能因为版本范围浮动而装出不同的依赖树,最终结果就是“在我电脑上跑得好好的,到你那就崩了”。
如果修改了package.json,但不想重新完整安装依赖,只希望生成新的 lockfile,可以运行:
npm install --package-lock-only这个命令只更新 lockfile,不会碰node_modules。在手动处理依赖冲突的提交时很有用。
另外一个常见的误解是:package-lock.json锁了版本,npm ci就能保证完全一致。但要注意,lockfile 是在特定 npm 版本下生成的,如果团队里有人用 npm 6、有人用 npm 10,生成的 lockfile 格式可能不同,行为也可能有细微差异。所以我建议统一 Node.js 和 npm 的版本,用.nvmrc或engines字段做约束。
4. 发布与维护 npm 包:从 login 到 publish 全流程
4.1 登录、权限与私有包配置
如果你写了工具库、组件库,打算发布到 npm 上给别人用,第一步是注册账号并在本地登录。
npm login按提示输入用户名、密码和邮箱即可。登录成功后可以用npm whoami确认当前身份,用npm logout退出。
发布包之前,包名要遵守 npm 的命名规则:不能有大写字母,不能以点或下划线开头,不能是 URL 保留名等。如果包名撞车,npm 会提示你换一个。还有一种方式是使用 scope 包,格式是@username/package-name,类似命名空间。
想创建一个带 scope 的包,可以执行:
npm init --scope=myaccount之后包名会自动带上@myaccount/前缀。scope 包可以设置为私有(private)或公开(public)。私有包只对授权用户可见,但 npm 官方私有包是收费的。不少公司会搭建私有的 npm 仓库来托管内部包,发布地址通过publishConfig.registry字段或.npmrc指向公司仓库。
发布前可以先模拟验证一下:
npm publish --dry-run它会打印出本次将要发布的内容和操作,但不会真正上传。这个命令被我当作发布前的安全检查。
4.2 发布前检查与常用字段
发包最怕的是把一堆无关文件传到 npm 上。所以我每次发之前都会配置files字段,白名单指定要包含的文件。
比如一个简单的库:
{ "name": "my-lib", "version": "1.0.0", "main": "dist/index.js", "module": "dist/index.mjs", "types": "dist/index.d.ts", "files": ["dist", "README.md"] }main字段是 CommonJS 入口,module是 ESM 入口,types是 TypeScript 类型声明入口。Node.js 较新版本也会读取exports字段,它能更精细地控制哪些子路径可以被外部引用,避免内部文件被直接 import。
如果你有构建步骤,发布前一定要保证产物已经构建好。通常会在prepublishOnly脚本里放构建命令:
{ "scripts": { "build": "tsc", "prepublishOnly": "npm run build" } }这样每次执行npm publish,npm 会自动先跑构建。如果构建失败,发布也会被中断,避免把老产物发出去。
.npmignore也可以用来排除文件,但我的建议是优先用files白名单,更可控。因为你不可能记得每次新增一个临时文件后去更新.npmignore,但白名单天然限制发布范围。
4.3 版本号管理与语义化版本
npm 包遵循语义化版本号,格式是主版本号.次版本号.修订号,对应 Major.Minor.Patch。
- 主版本号:发生不兼容的 API 变更。
- 次版本号:向后兼容的功能新增。
- 修订号:向后兼容的缺陷修复。
手动改版本号容易出错,npm 提供了npm version命令:
npm version patch npm version minor npm version major执行后会自动更新package.json里的版本号,如果项目是 Git 仓库,还会自动打一个形如v1.0.1的 tag。
想要发布预发布版本,比如 beta 版:
npm version prerelease --preid=beta这会把版本号设置为1.0.1-beta.0。发布这种版本时,建议指定发布标签:
npm publish --tag beta用户安装时用npm install package@beta就能拉到预发布版,而npm install package仍会安装最新稳定版。这是我强烈推荐的发布习惯,可以避免把不稳定版本推给所有用户。
4.4 废弃、撤销与权限管理
包发布之后不是完全不能动。如果要提醒用户某个版本有问题,用npm deprecate:
npm deprecate my-lib@"< 1.2.0" "存在安全问题,请升级到 1.2.0"用户安装时会在终端看到这条警告,但包仍然可以安装。如果你不小心发布了敏感信息,需要紧急移除某个版本,可以用:
npm unpublish my-lib@1.0.1 --force但 npm 对 unpublish 有严格限制:如果一个包发布超过 72 小时,或者版本被大量依赖,通常无法直接 unpublish,只能 deprecate。所以我的建议永远是:宁可 deprecate,也不要轻易 unpublish,因为删包会让所有依赖它的项目瞬间炸掉。
管理协作者可以用:
npm owner ls <package> npm owner add <username> <package> npm owner rm <username> <package>设置包公开或私有:
npm access public <package> npm access restricted <package>这些命令虽然不常用,但在团队协作发布包的时候非常重要。
5. 常见报错与排查技巧:这些坑我基本都踩过
5.1 权限与文件占用类报错:EACCES / EBUSY / EPERM
报错npm ERR! code EBUSY在 Windows 上非常常见,一般伴随着syscall rename或npm ERR! errno -4082。最典型的场景是:你开着编辑器、终端进程,或者杀毒软件正在扫描 node_modules 目录,npm 想要替换某个文件时发现文件被占用,命名失败。
解决办法按优先级排列:
- 关掉编辑器(VS Code、WebStorm 等)、终端窗口、Node 进程。
- 关闭杀毒软件或把 node_modules 目录加入信任区。
- 用
rimraf强制删除 node_modules:npx rimraf node_modules - 清缓存后重新安装:
npm cache verify npm install
EACCES常见于 Linux/macOS 下全局安装时权限不足。很多教程会让你sudo npm install -g xxx,这是非常不推荐的做法。长期使用 sudo 会导致 npm 全局目录的文件归属混乱,以后每次都要 sudo。更好的办法是使用 Node 版本管理工具,例如 nvm,将全局目录放在用户目录下,从根本上避免权限问题。
EPERM也经常出现在 Windows 上,通常也是文件占用或权限不足,排查逻辑和EBUSY类似。
5.2 依赖冲突与解析错误:ERESOLVE / peerDependencies
npm 7 开始采用了更严格的依赖解析规则,因此你可能会看到:
npm ERR! ERESOLVE overriding peer dependency npm ERR! Found: react@18.2.0 npm ERR! node_modules/react npm ERR! peer react@"^17.0.0" from some-lib@1.0.0意思是某个包(some-lib)声明了 peer 依赖,要求 react 必须是 17.x,但项目中实际安装的是 react 18。peer 依赖通常不是这个包自己写死的,而是希望宿主项目配合提供对应版本。
解决思路有几个:
- 手动协调版本,把 react 降到 17.x,或者找到 compatible 版本的 some-lib。
- 如果只是某个已知的无害冲突,可以临时用
npm install --legacy-peer-deps跳过检查。 - 借助 npm 的
overrides字段,强制指定某个传递依赖的版本。
overrides的写法在package.json里:
{ "overrides": { "some-lib": { "react": "^18.2.0" } } }但要注意,overrides是强制覆盖依赖范围,可能会掩盖上游包真正的问题,使用前需要评估风险。我在实际项目中,优先尝试第一种,实在搞不定再用 overrides。
5.3 原生模块与 node-gyp 相关报错
装某些依赖时,你可能会看到node-gyp、python2、Visual Studio等关键词。典型报错:
npm ERR! gyp verb check python checking for python executable "python2" npm ERR! cannot find native binding这是因为有些包并不是纯 JS 代码,比如老旧的node-sass、sharp、bcrypt等,需要在你本地编译 C/C++ 原生部分。编译需要系统里有 Python、C++ 编译工具链,Windows 上还需要 Visual Studio Build Tools。
我的建议是:优先找替代品。比如node-sass已经停止维护,直接用sass替代,npm install -D sass即可,不需要原生编译。其他实在绕不过去的包,再按官方文档安装编译工具:
- Windows:安装
windows-build-tools(用管理员 PowerShell 运行)。 - macOS:确保安装了 Xcode Command Line Tools。
- Linux:安装
build-essential和 Python。
另外,很多原生模块会提供预编译二进制,npm 默认会先下载预编译产物;如果下载失败,才会尝试本地编译。这时报错往往和网络有关,先换镜像源再试,往往就好了。
5.4 网络与源相关的报错:EUNSUPPORTEDPROTOCOL / workspace 协议 / deprecated
npm ERR! code EUNSUPPORTEDPROTOCOL和unsupported URL type "workspace:"常见于你把包含workspace:协议的包直接安装到普通项目里。比如从 monorepo 仓库复制了一个包的路径去安装,而这个包的依赖引用了workspace:*。普通 npm 不认识workspace:协议,只有在 pnpm、yarn workspace 环境里才支持。
解决办法:要么回到 monorepo 根目录执行 install,整体识别 workspace;要么把依赖里的workspace:*改成具体的版本号或file:路径。
还有一种高频的npm WARN deprecated node-domexception@1.0.0: use your platform's native dome只是提示某个依赖包被弃用。它不一定是错误,除非你确实还在使用这个包的功能。遇到 deprecated 警告,最好顺着依赖链找到顶层包,升级顶层依赖或换替代品,避免存量废弃代码积累安全问题。
网络层还有一种报错:
npm ERR! requestError hostname/ip does not match这通常发生在配置了自定义 registry 或代理时,证书校验失败。检查.npmrc或者环境变量里的 HTTPS_PROXY 是否正确。如果公司网络必须走 HTTP 代理,确认代理地址和端口没写错,并且已经加进 npm 配置:
npm config set proxy http://user:pass@proxy-host:port如果不是必须使用代理,直接清掉相关配置:
npm config delete proxy npm config delete https-proxy5.5 其他高频问题:audit / doctor / cache
npm audit用于检查依赖的安全漏洞。执行后它会列出有漏洞的包和修复建议,npm audit fix会自动尝试升级到修复版本,npm audit fix --force会激进地升级大版本,但可能带来破坏性变更。我在 CI 里通常执行npm audit --audit-level=high来把关严重漏洞,高危直接让流水线失败。
npm cache verify是检查缓存完整性,npm cache clean --force是清空缓存。注意,不要一遇到安装失败就清缓存,大部分问题不是缓存造成的。只有当安装出现明显的包文件损坏、校验和错误时才需要清理。
还有一个使用颇多的npm doctor,它会检查环境健康度,包括 npm 版本、Node 版本、全局权限、缓存路径等。如果你安装了多个 Node 版本,或者怀疑环境被改乱了,可以先跑一下npm doctor看看提示,往往能指出方向。
另外,热词里常出现npm run serve报“this dependency was not found”。这种情况九成是自己改了代码,但依赖没装全,或者引用的文件路径写错。建议先npm install,再看是不是少装了某个模块,最后检查 import 的路径和大小写。
最后分享一点我的习惯
npm 相关的问题,很多都不是“命令不会”,而是“不知道从哪里查起”。现在我的一般流程是:先看报错的第一行和最后一行,确定是权限、网络还是依赖解析问题;然后用npm config list看配置,用npm list看依赖结构,用npm why看依赖来源;最后才是清理缓存、重装 node_modules 这种重手段。
还有个小建议:项目里尽量统一 Node 版本,比如用 nvm 管理本机版本,在项目根目录放一个.nvmrc记录版本号。npm 本身迭代很快,不同版本的命令行为差异不小,统一版本能少踩很多莫名其妙的坑。
这篇内容基本把我日常用得上的 npm 命令和报错排查经验都过了一遍。以后你再遇到 npm 的问题,先别急着删 node_modules,按照上面这些方法一步步排查,大概率能在几分钟内定位到根因。