---
title: "npm 镜像源怎么设置：pnpm、yarn、bun 换源回切与装包慢排查"
description: "给出当前可用的 npm 镜像源地址，以及 npm、pnpm、yarn v1/Berry、bun 的全局、项目级和单次换源写法和回切方法，并讲清二进制包下载、lockfile 写死地址和怎么判断装包慢在哪一层。"
url: https://cdnping.org/blog/npm-registry-mirror-china-setup
language: zh-CN
published: 2026-10-21
category: "开发工具"
tags: ["npm","pnpm","yarn","bun","镜像源","前端工程"]
source: cdnping.org
license: Free to quote and summarize with a link to the url above.
---
# npm 镜像源怎么设置：pnpm、yarn、bun 换源回切与装包慢排查

国内最常用的 npm 镜像源地址是 `https://registry.npmmirror.com`，官方源是 `https://registry.npmjs.org`。旧的 `registry.npm.taobao.org` 早已停用，配置里还写着它的话，要尽快换掉。换源只解决“包的元数据和 tarball 从哪下”，装包慢的另一半原因往往在二进制下载、lockfile 和本地网络，下面分开讲。

## 先确认：现在用的是哪个源？

改之前先看清现状，很多“换了源还是慢”的问题，其实是配置被别的地方覆盖了。

```bash
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` 里写什么都不生效。

再顺手查一下老域名有没有残留：

```bash
grep -rn "npm.taobao.org" ~/.npmrc ~/.yarnrc ~/.yarnrc.yml .npmrc .yarnrc .yarnrc.yml \
  package-lock.json yarn.lock 2>/dev/null
```

## 各个包管理器怎么换源？

每种工具都给出三种写法：全局（只影响你这台机器）、项目级（跟着仓库走，团队成员一致）、单次（只这一条命令）。

### npm

```bash
# 全局：写入 ~/.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 一样有效。

```bash
pnpm config set registry https://registry.npmmirror.com   # 全局
pnpm install --registry=https://registry.npmmirror.com    # 单次
```

### yarn v1（Classic）

yarn v1 会读 `.npmrc`，也有自己的 `.yarnrc`。

```bash
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`。

```bash
# 项目级：写入当前目录的 .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`：

```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` 必须对官方源操作，镜像不接受发布。

```bash
# 永久回切
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 单独指定，不影响其他包：

```ini
# .npmrc
registry=https://registry.npmmirror.com
@your-company:registry=https://npm.your-company.example/
```

这里的私有源地址只是示例。

## 为什么换了源，CI 还在走旧地址？

原因通常在 lockfile。几种 lockfile 记录下载地址的方式不一样：

- **package-lock.json（npm）**：每个包都写了完整的 `resolved` URL。较新版本的 npm 有个 `replace-registry-host` 配置，默认值是 `npmjs`，意思是只把 `registry.npmjs.org` 替换成你当前配置的源。如果 lockfile 里写的是 npmmirror 或老淘宝域名，npm 不会替换，CI 换回官方源也照样去请求那个地址；老域名不可用时就直接失败。
- **yarn.lock（v1）**：同样写了完整 `resolved` URL，老域名需要手动替换。
- **yarn Berry 的 yarn.lock、pnpm-lock.yaml**：对默认 registry 上的包一般只记版本和 integrity，不写完整地址，受影响小。
- **bun.lock**：默认源的包通常不写完整地址，有疑问就用 grep 查一下。

处理办法有三种，按改动从小到大排：

```bash
# 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 换到哪里，这些下载都不跟着走。

判断方法：装包时看日志卡在哪一步。

```bash
npm install --foreground-scripts --loglevel=http
```

如果最后停在某个包的 `postinstall`，而且日志里出现 github.com、playwright 或 storage 相关的域名，那就是二进制下载慢，不是 registry 慢。

常见的处理方式是通过环境变量把下载地址指向镜像。npmmirror 提供了二进制镜像目录（`https://npmmirror.com/mirrors/`），具体路径以目录里实际存在的为准：

```bash
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 和二进制下载域名的连接时间。**

```bash
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 速度榜](/benchmark/cdn)，测法见[数据方法](/methodology)。关于这几段时间分别代表什么，可以参考 [AI API 延迟拆解](/blog/api-latency-connect-rtt-ttft)，原理和装包是一样的。

**第二步：按结果对照处理。**

| 现象 | 大概率原因 | 处理 |
| --- | --- | --- |
| `dns` 就要好几秒 | DNS 解析慢或被污染 | 换 DNS，参考 [DNS over HTTPS 配置指南](/blog/dns-over-https-setup-guide) |
| `dns` 正常，`connect` 很高 | 到源站路由远或丢包 | 换镜像源 |
| 镜像 `ttfb` 正常但安装仍慢 | 卡在二进制下载 | 按上一节配置二进制镜像 |
| 时快时慢，部分请求超时 | 代理规则或 IPv6 出口不一致 | 查分流和双栈 |
| 官方源和镜像都慢 | 本地网络本身有问题 | 先做整体网络自检 |

**第三步：检查代理。** npm 会读 `proxy`、`https-proxy` 配置和 `HTTPS_PROXY` 环境变量。开着全局代理时访问国内镜像，流量可能先绕到境外再回来，反而更慢。可以用 `npm config get https-proxy` 和 `env | grep -i proxy` 看有没有残留。分流规则怎么判断是否生效，见 [国内网站如何看到你的真实 IP](/blog/how-chinese-sites-see-your-real-ip) 和 [分流原理](/learn/split-tunneling)。

如果系统同时有 IPv4 和 IPv6，而代理只接管了其中一个，就会出现“同一个命令有时快有时超时”，排查方法见 [IPv6 代理不生效](/blog/ipv6-dual-stack-proxy-mismatch)。

**第四步：仍然说不清楚，就做一遍全链路检查。** [开发者网络自检清单（2026 版）](/blog/developer-network-self-check-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。
