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。