私服选型与搭建
September 09, 2020
选型
- cnpm
- Verdaccio
- Sinopia (已经不更新,放弃)
- Nexus
目前市面上常用的就这款,Sinopia 我们先想想,一个私服应该需要哪些功能
- 代理官方 Npm 仓库
- 支持多个 来源,比如 npm 源,cnpm 源,其他业务线 npm 私服,老npm私服
- 有权限控制,能集成公司现有的登录系统,不需要单独注册账号
- 定时清理缓存(这个超级总要,随着时间,缓存的是越来越多,不是开玩笑,500G 的硬盘都是不够用的)
- 支持 WebHook,不然你想实现个发布npm 组件后,消息通知到依赖方都做不了
- 支持大部分 npm 命令,至少要支持 npm dist tag ,不然 怎么区分发布 自己测试的 test 版本,和别人使用的版本
1,2 是大家都支持的,3 这个是个很强的需求,因为肯定是注册后的用户,才能 publish 组件,一般公司都有LDAP 权限系统(Gitlab 也是支持LDAP系统),如果能集成 LDAP,不用自己注册账号,直接用就好,4 这个点也个超级刚需,私服存储只会越来越大,我司用阿里云 500G 硬盘都不够用,所以需要有个机制,把长时间没有人 install 的包给删掉,但这个删掉又是不能随便删,自己公司发布的私有包最好不要删,不然都找不到,但是缓存的 npm,cnpm 组件是可以删掉了,没有了,用的时候再去 他们那里去拿就好,5,6 都是刚需
对照上面几个开源方案,Cpm/Verdaccio 权限系统不咋样,不支持定时任务,我自己强烈推荐 Nexus,我呆过的2家公司,最后都是从 Verdaccio 切到 Nexus 上了(额,是在我来之前切换的,不是我强扭的瓜)
Nexus 有完备的权限模块,支持 WebHook,而且还一直坚持更新,部署也非常简单,大家不要看到它是个Java写的,对部署安装怂起来,很简单的,实在不行就让你们运维帮忙部署下,大不了请喝水,唯一不足的是中文档不太多,下面我就好好讲讲 Nexus 平常的用法,基本覆盖来日常需求
首先 Nexus 分为开源版和企业版,大家下载开源版就好了,功能满足需求,企业版是有个免费咨询服务,有钱的可以买企业版
目前Nexus已经到了 3.x 版本,大家可以装最新版本,这里我跳过安装,LDAP集成,网上案例比较多,这里跳过,(Nexus 默认密码:admin/admin123)可以参考如下
Nexus 集成 LDAP using-nexus-3-as-your-repository-part-2-npm-packages
上面这几个都是非常重要且实用的功能,慢慢讲哦
Nexus 搭建 Npm 私服
基本点
Nexus 私服配置有下面几个要点
- proxy, 第三方源,比如 npm 中央仓库(https://registry.npmjs.org/),taobao(https://registry.npm.taobao.org/),
- hosted,这个就是们自己内部开发 package 上传后存储的目录
- group,字面意思,是个集合的意思,包含了上面面2个,我们是从这个路径下安装依赖

创建 proxy
点击 npm (proxy),创建代理,出现以下界面
上面标红框都是几个比较重要的点,Name是对这个代理取得名字,我这里就叫 npm,Remote storage 就是 remote 对应的的 url 了,下面几个仔细说说
Maximum component age
这个的含义是获取到 remote 包后,都长时间开始缓存,改成 -1, 意思是获取到就缓存
Maximum metadata age(超级重要)
多长时间区 remote 仓库获取下源信息, 默认是 30天 ,这个必须得改 比方说 vue 这个包,今天上午10点发布了一个版本 3.3.3,你在11点 执行 npm install vue@3.3.3,是会报 404 的,因为私服是30天获取一次 remote 仓库的信息,所以最好设置 30分钟以内,这样就可以快速获取到更新了,这个点很重要,我们之踩过这个坑,就是没有设置这个信息,同事经常报 404,好多次都获取最新的依赖,后来翻文档才发现还有这个设置,切记设置下
Negative Cache
都去掉,意思是不缓存没有获取到更新的信息
Cleanup(超级重要)
这个是设置清除缓存的选项,因为一直缓存,磁盘存储是越来越多,总有一天会爆满,需要定时清除 缓存的依赖,比如 30天都没有人用的依赖就应该清除掉,到时候再有人用的时候就自动去 remote 拉取,,是我们在 左侧菜单配置 Cleanup Policies 配置的,这里做个选择就好,具体配置,在后面讲
基本这样就配置好了 proxy 仓库
创建 hosted
hosted 公司内部 发布存储的包配置就比较简单,最后也不要定时清除的功能

创建 group

名称建议以公司简称命名(我这里name 假设叫 ppc),这样识别方便,然后选择 对应的 proxy,hosted 仓库就好了
设置好后 ,http://xxx.com/repository/ppc/ ,就是我们访问仓库的路径了,npm config set registry http://xxx.com/repository/ppc/, 我这里更推荐 nrm,动态切换,使用方便
npm i nrm -g
nrm ls
nrm add ppc http://xxx.com/repository/ppc/
nrm ls
nrm use ppc
然后 试试 npm install vue —verbose 看看日志信息,基本上就好了
设置用户名密码
local 账号
这里设置账号,密码,然后给这个账号设置那些是用更改的权限,然后本地 npm login 就可以使用这个账号了
LDAP 账号
使用上面这种方式,麻烦的地方时,每个人要 publish 包,都要配置个账号,比较麻烦(或者配置一个账号,大家都登录这个账号发布)
那我们也可以使用 公司集成好的LDAP账号体系,直接选择某个账号,赋予权限,这个账号就可以发布了,还在刚才页面选择 LDAP
在 Filter by user ID, 输入 LDAP账号搜索下,就可以赋予权限了
本地 publish
上面账号弄好后,我们平常本地可以 publish 包了
登录
需要登录 2 次,登录到 group 和 hosted
#
$ npm login --registry=http://xxx.com/repository/ppc/
$ npm login --registry=http://xxx.com/repository/youhosted/
会出现输入用户名和密码, 就是上面设置的用户名密码,如果用的是 LDAP 就是 LDAP 账号密码,登录成功后最终会在 ~/.npmrc(MAC,Lunix),C:\Users\admin\ .npmrc(Window) 中生成如下内容
registry=http://xxx.com/repository/ppc/
//xxx.com/repository/ppc/:_authToken=NpmToken.xxxx
//xxx.com/repository/youhosted/:_authToken=NpmToken.xxx
package.json 设置
注意 registry 设置的是 hosted 地址,不是 group 地址
"publishConfig" : {
"registry" : "http://xxx.com/repository/youhosted/"
}
发布不成功常见错误
如果遇到 403 错误或者“ENEEDAUTH”,把上面的登录方式重新来一遍 如果是 400 错误, 大概率是 package.json 忘记了设置,或者是 版本已经存在了,
npm ERR! publish Failed PUT 400
npm ERR! code E400
Repository does not allow updating assets: fe :
万能大法 要是方法都用了还是不行,大概率是是懵逼的在网上搜了资料,各种配置,导致出了问题,那就把 .npmrc 第一行以下都删除了,重新登录一遍
集成 gitlab ci/cd publish
看到上面写的本地发布是不是觉得很繁琐,难受的不行,还是得自动化了,参考我之前写的
删包
可能你手贱,publish 了个 包,你想删怎么办
没有 unpublish, 现在推荐使用 deprecate 命令,
deprecate 命令 只是标记一下此包废弃,在安装的时候会在命令行warn一下,但还是可以装
npm deprecate my-package@1.0.0
那你说,我非要删除咋办,那只能去 Nexus 的后台删除了,点击左侧菜单 browse,选择对应的 包
scope 使用
我们看 Babel,周边依赖都是 @babel/core,这前面这个叫命名空间,在本地 node_modules 下是放在同一个目录,方便查找,一眼看起来也是相关依赖,看着就专业
同样的我们内部的包也应该有这么个规范,建议以大的 bu 或者业务线来区分,比如假设是字节, @toutiao/test,@/douying/test2,@/feishu/test3,这样一眼就能明白是属于谁的,小一点的公司可以用 公司简称
WebHook
有时候我们会有这样的一些需求,publish 后,需要消息通知下 or 邮件 xxx,某个包升级了版本,依赖方收到消息后,就可以第一时间更新,这个 Nexus 也是支持的

点进去后,填写一个 api 地址,每次 publish 就会调用 这个api
私服搭建就基本讲完了
接下来还会写

如果喜欢可以点个赞,点赞是我持续写下去的动力,也可以关注我的微信公众号 「HC以为」