搭建属于自己的私有npm库

4,805 阅读5分钟

搭建属于自己的私有npm库

粗浅的方案对比

​ 最近在开发一个公共包,因为需要多人协作,使用npm link等都比较麻烦,所以搭建了下私有的npm库,这篇文章给自己做个记录,方便自己日后查找。且当业务规模较大了之后,我们一般会有自己的脚手架,自己的全局工具包等等。其中可能包含了自身的业务代码不能公开。我们都需要一个私有化的npm仓库。一般私有化的npm仓库有以下几种方法实现:

  1. 通过npm购买私有服务
  2. 通过git直接引用
  3. 通过开源项目直接搭建,例如cnpm、verdaccio、sinopia等

下面对各个方案进行一个粗浅的对比:

  • 官方私有npm服务:团队版$7/人/月这个价格就已经直接劝退,且不说npm在国内的网络情况不容乐观。
  • 直接安装git代码:直接通过npm install <git remote url>引入对应git代码确实有一定的便利性,但是当全局包多了之后不便于维护且权限难以管理
  • sinopia:基于Node.js实现的一个开源npm库,年久失修。最近一次提交是6年前,直接放弃。
  • cnpm:阿里出的npm私有方案,权限控制较为全面但是配置复杂,需要自己搭建mysql之类的数据库存储。
  • verdaccio:基于sinopia继续开发,目前维护很频繁而且配置简单,可以快速搭建。

安装

​ verdaccio提供了docker和全局包2种方式进行安装,下面是两种安装方式的详细步骤

docker部署

# 拉取verdaccio docker镜像
$ docker pull verdaccio/verdaccio:nightly-master

# 查看docker镜像
$ docker images
REPOSITORY                                TAG              IMAGE ID       CREATED        SIZE
verdaccio/verdaccio                       nightly-master   32713721fda5   16 hours ago   580MB

# 拷贝下面配置文件到本地~/docker/verdaccio目录
$ cp config.yaml ~/docker/verdaccio

# 启动docker容器
# -d: 在后台开启docker进程
# --name: 给容器指定一个名称
# --p: 将本机的4873端口映射到docker的4873端口
# --restart=always: 自动重启容器
# -v: 将本地~/docker/verdaccio目录挂载到docker的/verdaccio/conf目录
$ docker run --restart=always -d -v ~/docker/verdaccio:/verdaccio/conf --name verdaccio -p 4873:4873 verdaccio/verdaccio

# 查看docker容器
$ docker ps
CONTAINER ID   IMAGE                 COMMAND                  CREATED         STATUS         PORTS                                       NAMES
6aac1ea8707a   verdaccio/verdaccio   "uid_entrypoint /bin…"   2 minutes ago   Up 2 minutes   0.0.0.0:4873->4873/tcp, :::4873->4873/tcp   verdaccio

这样我们就完成了verdaccio在docker上的部署,其中我们将~/docker/verdaccio这个文件夹挂载到docker/verdaccio/conf文件夹,verdaccio在启动时会自动寻找/verdaccio/conf/config.yaml文件作为配置。

pm2部署

# 全局安装 verdaccio和pm2
$ npm install -g verdaccio pm2
# 通过pm2启动verdaccio
$ pm2 start verdaccio
[PM2] Starting /usr/local/bin/verdaccio in fork_mode (1 instance)
[PM2] Done.
┌─────┬──────────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id  │ name         │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├─────┼──────────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0   │ verdaccio    │ default     │ N/A     │ fork    │ 20889    │ 0s     │ 0    │ online    │ 0%       │ 10.2mb   │ cm       │ disabled │
└─────┴──────────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘

pm2的部署相对于docker需要安装node。但是相对的部署起来会更快捷,可以根据自己需要选择。

配置

上一节提到了两种部署方式,两种部署方式的配置文件存储地址也不相同,分别为:

docker: run时挂载的文件目录,这里我们挂载到~/docker/verdaccio/config.yaml

pm2: 一般默认路径是在~/.config/verdaccio/config.yaml,也可以通过pm2 logs查看

image-20210712150246898

# 存放软件所有软件包的目录
storage: ./storage
# 存放所有插件的目录
plugins: ./plugins

web:
  # 网站Title
  title: Verdaccio
  # 禁用Gravatar头像
  # gravatar: false
  # 排序方式 asc|desc
  # sort_packages: asc
  # 是否启用暗黑模式
  # darkMode: true
  # logo地址
  # logo: http://somedomain/somelogo.png
  # favicon地址
  # favicon: http://somedomain/favicon.ico | /path/favicon.ico

# i18n翻译配置
# i18n:
# 可用列表见:https://github.com/verdaccio/ui/tree/master/i18n/translations
#   web: en-US

auth:
  htpasswd:
    file: ./htpasswd
    # 最大注册用户数,默认为 "+inf".
    # 可用通过设置为-1禁止注册
    # max_users: 1000

# 上游npm库,这里可用设置为淘宝
uplinks:
  taobao:
    url: https://registry.npmjs.org/

packages:
	# 作用域包
  '@*/*':  
    # 允许所有人访问
    access: $all
    # 注册用户可访问
    publish: $authenticated
    # 注册用户可访问
    unpublish: $authenticated
    proxy: taobao

  '**':
    # 默认情况下所有用户 (包括未授权用户) 都可以查看和发布任意包
    # 你可以指定 用户名/分组名 (取决于你使用什么授权插件,默认的授权插件是内置的 htpasswd)
    # 访问权限有三个关键词: "$all", "$anonymous", "$authenticated"
    # $all 表示不限制,任何人可访问;
    # $anonymous 表示未注册用户可访问;
    # $authenticated 表示只有注册用户可访问
    access: $all

    # 允许所有注册用户发布/撤销已发布的软件包
    # (注意:默认情况下任何人都可以注册)
    publish: $authenticated
    unpublish: $authenticated

    # 如果私有包服务不可用在本地,则会代理请求到'taobao'
    proxy: taobao

# 您可以指定传入连接的HTTP /1.1服务器保持活动超时(以秒为单位)。
# 值为0会使http服务器的行为类似于8.0.0之前的Node.js版本,后者没有保持活动超时。
# 解决方法:通过给定的配置可以解决以下问题
server:
  keepAliveTimeout: 60
# 中间件
middlewares:
  audit:
    enabled: true

# 日志设置
logs: { type: stdout, format: pretty, level: http }

# 开放远程访问,允许所有IP
listen:
  - 0.0.0.0:4873

权限管理

角色划分

verdaccio默认的权限管理很简单甚至可以说是简陋。

packages下可以针对包进行权限控制,有三个关键字 "$all", "$anonymous", "$authenticated",分别为:

$all:所有人

$anonymous:未注册用户

$authenticated:已注册

基础的权限控制

在我目前的应用场景中,默认的权限控制已经能满足日常使用。我们可以通过关闭将 authhtpasswdmax_users设置为-1禁止注册,然后手动维护htpasswd文件来控制私有库的成员。htpasswd生成可以通过这个网站来生成

扩展

如果想要跟gitlab或者github等代码管理工具来关联权限,可以参考下社群的开源插件。如果需要根据自身业务进行权限管理的话,可以尝试下自己实现权限管理插件,具体参考权限控制插件

  • verdaccio-bitbucket:verdaccio Bitbucket 认证插件。
  • verdaccio-bitbucket-server:verdaccio 的 Bitbucket 服务器身份验证插件。
  • verdaccio-ldap:verdaccio 的 LDAP 身份验证插件。
  • verdaccio-active-directory:verdaccio 的 Active Directory 身份验证插件
  • verdaccio-gitlab:使用 GitLab 个人访问令牌进行身份验证
  • verdaccio-gitlab-ci:启用 GitLab CI 来针对 verdaccio 进行身份验证。
  • verdaccio-htpasswd:基于 htpasswd 文件插件(内置)的 verdaccio 身份验证
  • verdaccio-github-oauth:verdaccio 的 Github oauth 认证插件。
  • verdaccio-github-oauth-ui:verdaccio 登录按钮的 GitHub OAuth 插件。
  • verdaccio-groupnames:用于使用 $group 语法处理动态组关联的插件。与 ldap 插件配合使用效果最佳。

管理npm仓库源

因为国内的网络环境,一般我们都会给npm设置成淘宝源。这里我们将npm切换到私有库也可以参考这个方法

$ npm config set registry http://127.0.0.1:4873

这个方法能够直接将npm切换到私有库,但是当我们有多个npm的源时这样切换就显得比较麻烦了。所以这里推荐使用nrm来管理npm的源。

# 全局安装nrm
$ npm install -g nrm

# 添加私有库
$ nrm add localhost http://127.0.0.1:4873

# 查看现有的npm源
$ nrm ls
* npm -------- https://registry.npmjs.org/
  yarn ------- https://registry.yarnpkg.com/
  cnpm ------- http://r.cnpmjs.org/
  taobao ----- https://registry.npm.taobao.org/
  nj --------- https://registry.nodejitsu.com/
  npmMirror -- https://skimdb.npmjs.com/registry/
  edunpm ----- http://registry.enpmjs.org/
  localhost -- http://127.0.0.1:4873/
# 设置npm源
$ nrm use localhost 

npm包发布

注册

# 注册用户,这里因为方便演示,所以没有关闭注册。
$ npm adduser
npm notice Log in on http://127.0.0.1:4873/
Username: yourusername
Password:
Email: (this IS public) xxxxxx@qq.com
Logged in as yourusername on http://127.0.0.1:4873/.

发布

# 登录用户
$ npm login
npm notice Log in on http://127.0.0.1:4873/
Username: yourusername
Password:
Email: (this IS public) xxxxxx@qq.com
Logged in as yourusername on http://127.0.0.1:4873/.
# 查看当前登录用户
$ npm who am i
yourusername

发布

# 发布当前包
$ npm publish
...
npm notice === Tarball Details === 
npm notice name:          y2t                                     
npm notice version:       1.0.12                                  
npm notice filename:      y2t-1.0.12.tgz                          
npm notice package size:  114.8 kB                                
npm notice unpacked size: 247.0 kB                                
npm notice shasum:        cabc64af1e186fcbc735b6d0bf818185412e95fc
npm notice integrity:     sha512-8qtY3OlzEDTSI[...]yD1GJe8nkPv1g==
npm notice total files:   65                                      
npm notice 
+ y2t@1.0.12
# 最后看到 + [你的包名@版本号]既可