npm 镜像源怎么设置:pnpm、yarn、bun 换源回切与装包慢排查
国内最常用的 npm 镜像源地址是 https://registry.npmmirror.com,官方源是 https://registry.npmjs.org。旧的 registry.npm.taobao.org 早已停用,配置里还写着它的话,要尽快换掉。换源只解决“包的元数据和 tarball 从哪下”,装包慢的另一半原因往往在二进制下载、lockfile 和本地网络,下面分开讲。
先确认:现在用的是哪个源?
改之前先看清现状,很多“换了源还是慢”的问题,其实是配置被别的地方覆盖了。
npm config get registry
npm config list # 看每一项来自哪个配置文件
pnpm config get registry
yarn config get registry # yarn v1
yarn config get npmRegistryServer # yarn Berry (v2+)
npm 的配置按优先级从高到低是:命令行参数 > 环境变量(NPM_CONFIG_REGISTRY / npm_config_registry)> 项目里的 .npmrc > 用户目录的 ~/.npmrc > 全局配置。如果 CI 里设置了环境变量,你在项目 .npmrc 里写什么都不生效。
再顺手查一下老域名有没有残留:
grep -rn "npm.taobao.org" ~/.npmrc ~/.yarnrc ~/.yarnrc.yml .npmrc .yarnrc .yarnrc.yml \
package-lock.json yarn.lock 2>/dev/null
各个包管理器怎么换源?
每种工具都给出三种写法:全局(只影响你这台机器)、项目级(跟着仓库走,团队成员一致)、单次(只这一条命令)。
npm
# 全局:写入 ~/.npmrc
npm config set registry https://registry.npmmirror.com
# 项目级:在项目根目录建 .npmrc
echo "registry=https://registry.npmmirror.com" > .npmrc
# 单次
npm install --registry=https://registry.npmmirror.com
pnpm
pnpm 读的是同一套 .npmrc,所以上面 npm 的项目级写法对 pnpm 一样有效。
pnpm config set registry https://registry.npmmirror.com # 全局
pnpm install --registry=https://registry.npmmirror.com # 单次
yarn v1(Classic)
yarn v1 会读 .npmrc,也有自己的 .yarnrc。
yarn config set registry https://registry.npmmirror.com # 全局,写入 ~/.yarnrc
echo 'registry "https://registry.npmmirror.com"' > .yarnrc # 项目级
yarn install --registry https://registry.npmmirror.com # 单次
yarn Berry(v2 及以上)
Berry 不读 .npmrc,配置项也换了名字,是 npmRegistryServer。
# 项目级:写入当前目录的 .yarnrc.yml
yarn config set npmRegistryServer https://registry.npmmirror.com
# 全局:写入 ~/.yarnrc.yml
yarn config set -H npmRegistryServer https://registry.npmmirror.com
# 单次:用环境变量
YARN_NPM_REGISTRY_SERVER=https://registry.npmmirror.com yarn install
bun
bun 推荐写在 bunfig.toml,项目级放在仓库根目录,全局放在 ~/.bunfig.toml:
[install]
registry = "https://registry.npmmirror.com"
较新的 bun 也会读取 .npmrc 里的 registry,并且认 NPM_CONFIG_REGISTRY 环境变量。团队里如果同时有人用 npm 和 bun,项目级 .npmrc 是最省事的共同配置。
对照表
| 工具 | 项目级配置文件 | 配置项 | 单次 |
|---|---|---|---|
| npm | .npmrc | registry | --registry= |
| pnpm | .npmrc | registry | --registry= |
| yarn v1 | .yarnrc 或 .npmrc | registry | --registry |
| yarn Berry | .yarnrc.yml | npmRegistryServer | YARN_NPM_REGISTRY_SERVER= |
| bun | bunfig.toml 或 .npmrc | install.registry | NPM_CONFIG_REGISTRY= |
发包或要拿最新版本时,怎么回切官方源?
镜像站从官方同步,新发布的版本可能要等一段时间才出现。另外 npm publish、npm login 必须对官方源操作,镜像不接受发布。
# 永久回切
npm config set registry https://registry.npmjs.org
yarn config set npmRegistryServer https://registry.npmjs.org # Berry
# 只在发布时临时指定
npm publish --registry=https://registry.npmjs.org
如果公司有私有源,可以只给某个 scope 单独指定,不影响其他包:
# .npmrc
registry=https://registry.npmmirror.com
@your-company:registry=https://npm.your-company.example/
这里的私有源地址只是示例。
为什么换了源,CI 还在走旧地址?
原因通常在 lockfile。几种 lockfile 记录下载地址的方式不一样:
- package-lock.json(npm):每个包都写了完整的
resolvedURL。较新版本的 npm 有个replace-registry-host配置,默认值是npmjs,意思是只把registry.npmjs.org替换成你当前配置的源。如果 lockfile 里写的是 npmmirror 或老淘宝域名,npm 不会替换,CI 换回官方源也照样去请求那个地址;老域名不可用时就直接失败。 - yarn.lock(v1):同样写了完整
resolvedURL,老域名需要手动替换。 - yarn Berry 的 yarn.lock、pnpm-lock.yaml:对默认 registry 上的包一般只记版本和 integrity,不写完整地址,受影响小。
- bun.lock:默认源的包通常不写完整地址,有疑问就用 grep 查一下。
处理办法有三种,按改动从小到大排:
# 1. 单次让 npm 替换所有 resolved 的域名
npm ci --replace-registry-host=always
# 2. 把 lockfile 里的老域名统一换成官方源(提交前看一眼 diff)
sed -i 's#https://registry.npm.taobao.org#https://registry.npmjs.org#g' package-lock.json
# 3. 删掉 lockfile 重新生成(会顺带升级依赖,慎用)
我们的建议是:lockfile 里统一保留官方源地址,各人的机器和 CI 通过 .npmrc 或环境变量决定实际走哪个源。这样 lockfile 不随个人习惯来回变,换源也不用改仓库。integrity 校验值和下载地址无关,镜像下来的 tarball 内容一致就能通过。
为什么 electron、sharp、playwright 换了源还是慢?
这类包的 npm 包本身很小,真正大的东西是在 postinstall 阶段从另一个域名下载的:electron 从 GitHub Releases 拉二进制,playwright 和 puppeteer 下载浏览器,老版本的 node-sass 下载编译好的 binding。registry 换到哪里,这些下载都不跟着走。
判断方法:装包时看日志卡在哪一步。
npm install --foreground-scripts --loglevel=http
如果最后停在某个包的 postinstall,而且日志里出现 github.com、playwright 或 storage 相关的域名,那就是二进制下载慢,不是 registry 慢。
常见的处理方式是通过环境变量把下载地址指向镜像。npmmirror 提供了二进制镜像目录(https://npmmirror.com/mirrors/),具体路径以目录里实际存在的为准:
export ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/"
export PLAYWRIGHT_DOWNLOAD_HOST="https://npmmirror.com/mirrors/playwright"
export SASS_BINARY_SITE="https://npmmirror.com/mirrors/node-sass"
几点要注意:
- 新版 sharp 的预编译文件改成以
@img/sharp-*的 npm 包发布,会随 registry 一起走镜像,一般不需要再配二进制地址;老版本才需要。 - 很多旧教程把
electron_mirror=...这类键写进.npmrc。新版 npm 对不认识的配置项会给出警告,并提示以后的大版本里将不再支持。放在环境变量或 CI 的 env 里更稳。 - puppeteer 新版本的下载变量名和以前不同,以它的官方文档为准。
- CI 里如果不需要浏览器,可以用对应工具的“跳过下载”变量,直接省掉这一步。
慢到底慢在哪一层?一个判断流程
换源是在解决“离源站太远”的问题。如果慢在 DNS、代理或者本地网络,换源没用。可以按下面的顺序查:
第一步:分别测 registry 和二进制下载域名的连接时间。
for u in https://registry.npmjs.org/react \
https://registry.npmmirror.com/react \
https://github.com; do
curl -o /dev/null -s -w "$u\n dns=%{time_namelookup}s connect=%{time_connect}s tls=%{time_appconnect}s ttfb=%{time_starttransfer}s total=%{time_total}s\n" "$u"
done
这几个时间是累计值:dns 是域名解析,connect 到 TCP 建好,tls 到握手完成,ttfb 到服务器返回第一个字节。这个拆法和 cdnping 在线测速 的口径一致:首页对公共前端 CDN 分别测“首次连接”(含 DNS 与 TLS 握手)和“往返”(连接复用后 3 次请求的中位数)。在浏览器里打开测一遍,可以快速看出当前网络到境外和境内 CDN 节点的大致差距;各家 CDN 的横向数据见 CDN 速度榜,测法见数据方法。关于这几段时间分别代表什么,可以参考 AI API 延迟拆解,原理和装包是一样的。
第二步:按结果对照处理。
| 现象 | 大概率原因 | 处理 |
|---|---|---|
dns 就要好几秒 | DNS 解析慢或被污染 | 换 DNS,参考 DNS over HTTPS 配置指南 |
dns 正常,connect 很高 | 到源站路由远或丢包 | 换镜像源 |
镜像 ttfb 正常但安装仍慢 | 卡在二进制下载 | 按上一节配置二进制镜像 |
| 时快时慢,部分请求超时 | 代理规则或 IPv6 出口不一致 | 查分流和双栈 |
| 官方源和镜像都慢 | 本地网络本身有问题 | 先做整体网络自检 |
第三步:检查代理。 npm 会读 proxy、https-proxy 配置和 HTTPS_PROXY 环境变量。开着全局代理时访问国内镜像,流量可能先绕到境外再回来,反而更慢。可以用 npm config get https-proxy 和 env | grep -i proxy 看有没有残留。分流规则怎么判断是否生效,见 国内网站如何看到你的真实 IP 和 分流原理。
如果系统同时有 IPv4 和 IPv6,而代理只接管了其中一个,就会出现“同一个命令有时快有时超时”,排查方法见 IPv6 代理不生效。
第四步:仍然说不清楚,就做一遍全链路检查。 开发者网络自检清单(2026 版) 把出口 IP、DNS、分流和测速串成了一个顺序,适合在新机器或新 CI runner 上跑一遍。
换源前后的检查表
-
npm config list里没有npm.taobao.org - 项目
.npmrc、.yarnrc.yml或bunfig.toml和团队约定一致 - lockfile 里没有老域名;npm 项目的
resolved统一用官方源 - CI 的环境变量没有覆盖掉项目配置(或者覆盖是有意的)
- 发布流程显式写了
--registry=https://registry.npmjs.org - electron、playwright 等二进制下载地址放在环境变量里,不放在
.npmrc - 用 curl 测过 registry 和二进制域名的连接时间,确认慢在哪一层
小结
镜像源本身只要改一行。换了还慢时,先用 curl 或在线测速把 DNS、连接、首字节时间拆开,再按上面的表决定是改源、配二进制镜像,还是查代理和 DNS。