npm/yarn/pnpm切换Nexus仓库源时如何避免重复下载包?
我在公司项目里用Nexus搭建了私有npm仓库,平时用npm config set registry切换内外网源。但发现每次切换回公共仓库后,之前通过Nexus下载的包还会重复下载,缓存好像没起作用。试过删除node_modules和缓存文件,但依然卡在下载阶段报404 Not Found错误:
npm ERR! 404 Not Found - GET https://registry.npmjs.org/lodash@^4.17.21
npm ERR! 404
npm ERR! 404 'lodash@^4.17.21' is not in the npm registry.
换yarn和pnpm也出现类似问题,搞不懂是仓库配置还是缓存机制的问题,有没有什么统一的解决方案?
https://nexus.example.com/repository/npm-group/lodash/-/lodash-4.17.21.tgz),而公共仓库压根不认识这个 URL,所以会去公共 registry 请求这个路径——结果当然是 404。更严重的是,如果 Nexus 上配置了 “禁止代理缓存过期” 或 “强制离线模式”,或者你手动删过缓存但没清掉 lockfile 里的 tarball 字段,就会导致工具继续尝试访问那些失效的 URL。
我分三步说怎么彻底解决,按优先级来:
第一步:确认 Nexus 的代理配置是否合理
进入 Nexus UI,找到你的 npm proxy repository(比如叫
npm-proxy),检查:-
Remote Storage里是不是指向了https://registry.npmjs.org/(注意最后带斜杠)-
Download Remote Indexes要勾上,否则本地无法查到最新版本-
Storage标签页里Blob store要用独立的(别用 default)- 最关键的是
Proxy标签页里的Negative Cache Duration,建议设成0或很小的值(比如 60 秒),否则 Nexus 会缓存 404 结果导致你以为包不存在如果你用的是 group 类型仓库(比如
npm-group),确保它把 proxy 放在最前面,且 host(私有发布仓库)在后面。第二步:统一清理三类缓存(不同工具方式不同)
很多人只删了
~/.npm/_cacache,但忘了另外两个致命缓存源:- npm 会缓存 tarball 的完整 URL 到
~/.npm/_cacache/content-v2和~/.npm/_cacache/index-v5,但更坑的是package-lock.json里可能直接写死了 tarball 字段(尤其是用过npm install --package-lock-only之后)- yarn v1/v3 会把 URL 存在
~/.yarn-cache和yarn.lock的resolved字段里- pnpm 用的是
~/.pnpm-store和pnpm-lock.yaml的dependencies下的resolved字段所以必须三连清:
1. 删除本地缓存目录(按工具):
- npm:
rm -rf ~/.npm/_cacache- yarn:
rm -rf ~/.yarn/cache(v1)或rm -rf ~/.yarn/berry/cache(v3)- pnpm:
pnpm store prune(推荐)或直接删~/.pnpm-store2. 强制忽略 lockfile 的 resolved 字段(关键!):
- npm 用
--no-package-lock或npm install --package-lock-only=false(新版支持)- yarn v1 加
--no-lockfile,v3 加--no-lockfile-update- pnpm 加
--lockfile-only后再pnpm install --no-lockfile-update(但更推荐直接删 lockfile 里所有resolved字段)3. 手动清掉 lockfile 里的 tarball URL(最彻底):
比如
package-lock.json里找到类似:直接把
resolved这一行删掉(或改成空字符串),让工具重新向 registry 请求最新 tarball 地址。注意:不能只删 URL 改成空字符串,要整个字段删掉,否则某些工具会报错。第三步:用统一的 registry 策略,避免手动切换
最省心的方式是别用
npm config set registry这种全局切换——它只改了当前用户的 registry 地址,但不会动 lockfile 和缓存里的 URL。改用以下任一方案:
- 用
.npmrc文件按项目隔离(推荐):在项目根目录放一个
.npmrc,内容:换公共仓库时,直接把这行注释掉或删掉(别用
#注释,有些老版本 npm 不认),然后重装依赖。这样 lockfile 不会被污染,因为每次都是新 registry 解析。- 如果必须用公共源,临时用
NPM_CONFIG_REGISTRY环境变量覆盖:这样只影响这一次 install,不会改全局配置,也不会让 lockfile 记录 Nexus 的 URL。
- 用
npmrc的save-prefix和cache配合:在项目根的
.npmrc里加:这样每个 CI 分支用独立缓存,本地开发切源时也不受影响。
最后说个真实踩坑经验:如果你用的是 Nexus 3.x,它有个隐藏坑——
npm proxy默认的Max Component Size是 100MB,如果某个包(比如chromium或electron)超过这个大小,Nexus 会直接返回 404,但日志里不报错。进Storage设置里把Max Component Size改成1024(单位 MB)再试,亲测解决过好几次类似问题。再补充一句:pnpm 的
shamefully-hoist或strict-peer-dependencies不会影响这个,但auto-install-peers如果开的话,会触发更多网络请求,建议关掉再试。按这三步走完,基本不会再有 404 问题了。如果还有,把你的
.npmrc和 Nexus 仓库配置贴出来,我帮你看看是不是配置文件里藏了什么奇怪参数。首先确认你的Nexus私有仓库配置了正确的uplink,确保它能代理到官方源。如果私有源没配好代理,切换回公共源时就会出现找不到包的问题。
然后重点来了,你需要统一缓存路径来避免重复下载。对npm、yarn和pnpm分别设置环境变量或配置:
对于npm,可以设置
npm config set cache指定一个全局缓存目录,比如~/.npm-cache,然后通过npm config set registry切换源时缓存就能复用。yarn的话稍微麻烦点,需要在
.yarnrc文件里加上--mutex network和--cache-folder配置,指定一个固定的全局缓存路径。pnpm也有类似的机制,可以通过
pnpm config set store-dir设置一个全局的store目录,保证不同源的包都能共享同一个存储位置。最后一个小技巧,如果你经常需要切换源,可以写个简单的脚本来同时切换registry和缓存路径,省得每次都手动设置。比如用shell写个函数:
这样每次切换源的时候,缓存路径也会跟着一起切换,能有效避免重复下载的问题。记得根据实际情况调整路径和域名。