一、问题场景与根因

很多公司的内网开发环境是完全离线的,代码、依赖都只能从内部私有源拿,但是用Lerna管理多包项目的时候,经常会遇到发布依赖超时的问题。比如上周我帮同事处理的一个项目:公司内网搭了私有npm源,但是Lerna配置没给全,发布的时候它默认会去查npm官方源,内网根本连不上,直接报“连接超时”。根因其实就是两个:一是Lerna不知道哪些源是内网允许的,没做源的白名单限制,到处乱找源;二是本地没有缓存代理,已经下载过的包下次还要再去拉,内网的网又卡又慢,自然超时。

二、应急处理核心思路

要解决这个问题,核心就是堵上两个漏洞:第一个是给Lerna加上“门禁白名单”——只允许它从我们指定的内部私有源或者预先约定好的源拿包,其他来源的请求直接拦下来;第二个是搭一个“本地快递柜”缓存代理——已经下载过的包都存在本地,下次需要直接从缓存拿,不用再跑外面的服务器拉,这样既能减少外网请求,又能提速,不会因为内网延迟超时。

三、具体操作步骤(基于Node.js/Lerna技术栈)

3.1 环境前提说明

咱们这个方案用单一技术栈:Node.js + npm + Lerna,适合大部分用Lerna管理的Node.js多包项目,环境是内网离线,已经有公司的私有npm源(比如地址是http://npm.xxx.com)。

3.2 配置镜像源白名单

白名单的作用就是告诉Lerna,哪些源是合法的可以用的,其他源一概不许碰。操作很简单,修改项目根目录下的.npmrc文件(如果没有就新建):

# 进入项目根目录(替换成你的实际项目路径)
cd your-lerna-project
# 创建或编辑.npmrc文件,逐行写入配置
echo "registry=http://npm.xxx.com" >> .npmrc # 全局默认用公司私有源拉所有包
echo "@company:registry=http://npm.xxx.com" >> .npmrc # 公司内部私有包的命名空间,只能从私有源拿
echo "lodash:registry=https://registry.npmjs.org" >> .npmrc # 例外:lodash包需从官方源拉,加入白名单
echo "strict-ssl=false" >> .npmrc # 内网若用HTTP源,临时关闭SSL校验(生产环境必须改回true)

这里要注意,白名单不能乱加源,每一条都是我们允许Lerna访问的地址,加多了就等于没加,起不到限制作用。

3.3 搭建本地缓存代理

缓存代理用local-npm就够了,轻量好装,专门存npm包的本地缓存,操作如下:

# 全局安装local-npm,作为本地缓存代理
npm install -g local-npm
# 启动local-npm,指定缓存目录(选空间大的盘)和监听端口
local-npm --port 3000 --cache ~/project-local-npm-cache
# 启动成功后会输出"Listening on :3000",说明代理服务正常运行

然后还要把npm的代理指向这个本地缓存,继续追加到.npmrc配置:

# 追加代理配置到.npmrc,让Lerna优先从本地缓存拉包
echo "proxy=http://localhost:3000" >> .npmrc
echo "https-proxy=http://localhost:3000" >> .npmrc

local-npm的逻辑很简单:它会自动同步所有我们拉过的npm包到本地,下次Lerna要包的时候,先问本地缓存有没有,有就直接拿,没有再去私有源拉,既省时间又不会超时。

3.4 Lerna项目的验证步骤

配置完之后,用Lerna的启动命令测试下能不能正常跑,确认配置生效:

# 用bootstrap命令初始化项目依赖,加--verbose看详细日志
lerna bootstrap --verbose

如果日志里显示“using registry http://npm.xxx.com”(源正确),还有“from cache”(走了本地缓存)的字样,就说明配置成功了,接下来发布也不会超时。

四、技术优缺点分析

4.1 优点

这个方案的优点很明显:一是配置速度快,几行命令就搞定,适合临时应急;二是灵活性强,白名单可以单独给个别包开例外,不用把所有包都锁死在私有源;三是缓存代理能大幅减少重复请求,内网环境下提速效果很明显,不会因为源延迟超时;四是安全性,白名单限制了源,避免Lerna误连外网的不安全源。

4.2 缺点

缺点也有:一是需要维护本地缓存,如果项目大,缓存会越来越占空间,要定期清理;二是临时关闭strict-ssl有安全风险,生产环境必须换回true,避免中间人攻击;三是local-npm的缓存同步是被动的,不会主动更新包,如果私有源同步了新包,可能要手动触发一下同步;四是如果Lerna版本和local-npm不兼容,可能会出缓存读取的问题,要注意版本匹配。

五、注意事项

这里要注意几个点,不然配置了也白搭:第一,公司私有源要定期同步官方源的常用包,不然local-npm找不到的话还是会超时;第二,本地缓存目录要选空间大的盘,别放系统盘,不然会占满影响系统运行;第三,生产环境一定要把strict-ssl改成true,避免内网HTTP源的安全漏洞;第四,白名单里的源要确认是内网能连通的,别填外网地址,不然等于没限制;第五,Lerna publish的时候也要走npm的源配置,只要配置了.npmrc就没问题,不用额外改publish命令的参数。

六、总结

这个方案是专门针对离线内网环境下Lerna发布超时的应急方案,核心就是用白名单限制源、用本地缓存代理减少请求,操作简单,见效快,适合临时解决问题,也可以长期用来优化多包项目的依赖获取速度。如果公司有条件,还可以把local-npm改成内网共享缓存,整个团队共用,不用每个人都搭本地的,效果会更好,毕竟内网共享缓存的同步和维护成本更低,适配多项目开发的场景。