前言
随着前端项目越来越多,尤其是内部的 js lib 库越来越多,怎么有效的管理 lib 库的发布,就变成一个很重要的问题了。
以之前做的 air-ui 来说,其实在进行版本发布的时候,为了保证不污染 gitlab 上的 master 分支,所以就专门写了脚本在版本发布的时候,进行分支切换来处理,具体步骤多又繁琐:1
2
3
4
5
6
7
81. 检查当前分支是否是远程的 master 分支,如果不是,返回错误
2. 执行 yarn dist, 生成 lib 目录
3. 将 lib 目录保存到一个 gitignore 的一个目录 lib_tmp
4. commit and push master 分支 (如果 status 有改变的话)
5. 切换到 master-release 分支,将 lib_tmp 的文件覆盖 lib 目录
6. commit and push master-release 分支
7. master-release 打 tag
8. 把临时文件 lib_tmp 删掉
这种流程是有一些缺点和问题的:
- 发布流程复杂化: 需要编写专门的脚本来确定哪些构建产物的代码需要发布,同时还需手动删除不必要的代码。
- 容易产生混淆: 使用
git tag来发布代码可能会引起混淆,因为它通常用于标记版本,而不是发布代码。 - 无法利用语义化版本控制的范围(例如:^1.0.0 或 ~1.0.0)来精确指定依赖的版本
但是如果我们有自己的 npm 库的话,其实对于库的发布就变得非常简单,只需要简单的 3 步:
- 更新
package.json中的版本号 - 代码构建
- 最后执行
npm publish命令,即发布成功
根本不需要对项目的代码做耦合。 而且随着项目的迭代和新增,内部维护自己的 js 库,不管是组件库,还是工具库,或者是业务库,其实都会变得越来越多。因此是需要搭建自己的内部 npm 库的。它不仅会简化js库发布流程,还可以增强前端各项目通用代码流通。
verdaccio 简介
我们使用 verdaccio 部署了npm 私有源, Verdaccio 是一个轻量级的私有 npm 代理注册服务器,它可以帮助你建立自己的私有仓库,对 npm 包进行管理。以下是 Verdaccio 的一些主要功能:
- 私有包管理:你可以使用 Verdaccio 来发布和存储你的私有包,这对于保护你的源代码和内部使用的包非常有用。
- 缓存代理:Verdaccio 可以作为一个 npm 代理,它会缓存所有从 npmjs.com 下载的公共包,这样即使你失去了与 npmjs.com 的连接,你仍然可以安装这些包。
- 权限控制:Verdaccio 支持用户认证和包权限控制,你可以控制谁可以访问和发布你的私有包。
- 易于扩展:Verdaccio 支持插件,你可以使用插件来扩展 Verdaccio 的功能,例如添加新的认证方法,改变存储方式等。
- 兼容性:Verdaccio 完全兼容 npmjs.com,你可以使用 npm 或者 yarn 等工具来与 Verdaccio 交互。
- 易于部署:Verdaccio 可以在多种环境中部署,包括 Docker,Kubernetes,云服务等。
- Web UI:Verdaccio 提供了一个用户友好的 web 界面,你可以在这个界面上搜索和管理你的包。
接下来开始进入实操环节
安装
Verdaccio 有多种安装,因为是安装在服务端,因此为了不污染服务器全局环境,我这边是使用 docker 来安装: Running Verdaccio using Docker
我的安装环境是 CentOS 7
安装 docker
1 | [root@VM-64-9-centos ~]# sudo yum install -y yum-utils |
安装镜像
1 | V_PATH=/etc/verdaccio; docker run -d -it --name verdaccio \ |
这边是直接用挂载宿主机 /etc/verdaccio 目录的方式来对 verdaccio 的持久化数据进行维护, -d 表示后台运行
不需要先拉取镜像,启动的时候,如果本地找不到镜像,会自己的 pull 线上的镜像
1 | [root@VM-1-3-centos conf]# V_PATH=/etc/verdaccio; docker run -d -it --name verdaccio -p 4873:4873 -v $V_PATH/conf:/verdaccio/conf -v $V_PATH/storage:/verdaccio/storage -v $V_PATH/plugins:/verdaccio/plugins verdaccio/verdaccio |
不过这边要注意一个细节,因为是走挂载的方式,所以启动 docker 时候的配置文件 config.yaml,我们要先创建好,直接拷贝官网 github 上的默认文件即可: config.yaml
记得重命名为
config.yaml, 完整路径是:/etc/verdaccio/conf/config.yaml
如果刚开始没有这个配置文件的话,启动 docker 的时候就会报这个错误:1
cannot open config file /verdaccio/conf/config.yaml: false
当 docker 启动之后,我们可以通过docker logs -f verdaccio 查看当前这个容器的当前 log 输出。
同时也因为启动成功,所以我们也可以查看 webui 界面,端口就是上面的 4873

配置文件分析
现在服务已经启动了,用的配置文件是默认的配置,我们来看下都有哪些配置,下面只列出 config.yaml 文件中有启用的配置:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56# 存放包的目录
storage: /verdaccio/storage/data
# 存放插件的目录
plugins: /verdaccio/plugins
# https://verdaccio.org/docs/webui
# webui 界面的配置
web:
title: Verdaccio
# https://verdaccio.org/docs/configuration#authentication
# 权限校验,通过 adduser 创建的用户信息,会放在这个文件
auth:
htpasswd:
file: /verdaccio/storage/htpasswd
# https://verdaccio.org/docs/configuration#uplinks
# 其他代理的资源库,在设置 packages 权限的时候,可以通过设置 proxy 来代理下载外部资源包,默认是走 npmjs 官网
# 当然也可以添加多个,比如也可以设置淘宝源,然后可以自己指定不同 scope package 包的时候,如果本私有库找不到,可以通过走不同的 uplink 资源库来进行代理下载
uplinks:
npmjs:
url: https://registry.npmjs.org/
# https://verdaccio.org/docs/protect-your-dependencies/
# https://verdaccio.org/docs/configuration#packages
# 包权限管理,可以根据不同的 scope 来设置不同权限,默认就是访问下载是所有人,但是 publish 和 unpublish 是要有用户登录权限才行
# 然后也可以通过配置 proxy 代理源,在当找不到包的时候,可以去外网下载包
packages:
'@*/*':
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: npmjs
'**':
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: npmjs
# https://verdaccio.org/docs/configuration#server
# 用来修改服务器属性
server:
keepAliveTimeout: 60
# https://verdaccio.org/docs/configuration/#audit
# 校验中间件
middlewares:
audit:
enabled: true
# https://verdaccio.org/docs/logger
# log 输出设置,也可以设置输出到 file
log: { type: stdout, format: pretty, level: http }
默认配置其实不多,并且官方文档其实说的很清楚了,这边不再赘述, 正常情况下,在有挂载 conf 和 storage 和 plugin 目录的情况下,配置项保持默认其实就够了,后面如果需要调整的话,下面会单独说明
实际操作
接下来我们来实际操作整个过程
本次测试的客户端的 node 版本是
16.20.0版本
1. 创建账号
要发布的话,肯定是要有一个账号的。默认情况下,肯定是没有账号的 (使用 npm whoami 查看当前用户,要指定源,不然就会指向默认源):1
2
3
4>npm whoami --registry http://43.139.27.159:4873/
npm ERR! code ENEEDAUTH
npm ERR! need auth This command requires you to be logged in.
npm ERR! need auth You need to authorize this machine using `npm adduser`
通过 adduser 创建一个1
2
3
4
5
6
7>npm adduser --registry http://43.139.27.159:4873/
npm WARN adduser `adduser` will be split into `login` and `register` in a future version. `adduser` will become an alias of `register`. `login` (currently an alias) will become its own command.
npm notice Log in on http://43.139.27.159:4873/
Username: zachke
Password:
Email: (this IS public) kebingzao@gmail.com
Logged in as zachke on http://43.139.27.159:4873/.
不过这边要注意一个细节,就是如果是用 docker 安装的话,因为用户新增的时候,会写入 htpasswd 文件,由于该文件是在宿主机上,也就是 /etc/verdaccio/storage/htpasswd 这个文件,而 verdaccio 容器中拥有自己的用户名,名字就叫 verdaccio,所以无法写入 root 用户拥有的文件。
所以这时候在创建的时候,就会报:1
npm ERR! 500 Internal Server Error - PUT http://43.139.27.159:4873/-/user/org.couchdb.user:zachke - internal server error
解决的方式也很简单,只要将宿主机的这个 storage 目录的 owner 设置为 verdaccio 用户即可。而且 docker 容器中的 uid 和 gid 和宿主机是共享的,只不过没有具体的名称。
因此我们通过 docker inspect verdaccio 查看 uid, 发现是 100011
2[root@VM-1-3-centos ~]# docker inspect verdaccio | grep UID
"VERDACCIO_USER_UID=10001",
至于 gid,就需要进入到这个容器中,并且打开用户组文件进行查找, 可以看到是 655331
2~ $ cat /etc/group | grep verdaccio
nogroup:x:65533:verdaccio
所以在宿主机改一下 storage 的权限即可,改成 verdaccio 的 user id,和 group id,也就是 10001 和 65533, -R 表示子目录也同样需要1
[root@VM-1-3-centos verdaccio]# sudo chown -R 10001:65533 /etc/verdaccio/storage
这样子就可以创建成功了:1
2>npm whoami --registry http://43.139.27.159:4873/
zachke
也可以在 storage/htpasswd 这个查看这个文件, 就可以发现已经有一个用户了1
2[root@VM-1-3-centos verdaccio]# cat /etc/verdaccio/storage/htpasswd
zachke:wKTp2Zn.123456:autocreated 2023-09-18T02:25:30.987Z
同时通过这个账号也可以登录 web ui 后台

既然有添加用户,那肯定有登录和登出:1
2npm login --registry http://43.139.27.159:4873/
npm logout --registry http://43.139.27.159:4873/
添加用户就默认登录了,如果要切换同一个源的不同用户,就要先登出,然后再登录
2. 创建项目
接下来就可以创建一个新的项目, 使用 npm init 指令可以快速生成一个只包含 package.json 文件的项目:1
2
3$ mkdir testlog
$ cd testlog/
$ npm init
基本上一路默认下去,就可以创建一个项目了。
如果不想一个一个项的配置,直接使用
npm init -y指令创建,就会生成一份全部走默认值的package.json文件
这时候这个 testlog 项目就会有一个 package.json 的文件了1
2
3
4
5
6
7
8
9
10
11{
"name": "testlog",
"version": "1.0.0",
"description": "is test log",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
单独只有这个文件肯定是不行,因为上面的 main 字段已经默认入口文件是 index.js, 所以这时候需要再创建一个 index.js 文件来当作入口文件, 内容如下:1
2
3
4
5function mylog() {
console.log('mylog: ', ...arguments);
}
module.exports = {mylog};
功能很简单,就是针对 console.log 做了一层封装,加了一个 log 输出前缀
3. 发布项目
接下来我们就发布这个项目,版本就是上面的 version: 1.0.0:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18\testlog> npm publish --registry http://43.139.27.159:4873/
npm notice
npm notice 📦 testlog@1.0.0
npm notice === Tarball Contents ===
npm notice 93B index.js
npm notice 214B package.json
npm notice === Tarball Details ===
npm notice name: testlog
npm notice version: 1.0.0
npm notice filename: testlog-1.0.0.tgz
npm notice package size: 332 B
npm notice unpacked size: 307 B
npm notice shasum: 8e13c7124703cf5a6fe8d73dce54ef541f8edcb4
npm notice integrity: sha512-vUYCEp6/Lw7cj[...]vYziTPKdNFRBg==
npm notice total files: 2
npm notice
npm notice Publishing to http://43.139.27.159:4873/
+ testlog@1.0.0
这时候就可以再 web 后台看到了:

可以看到首页列表中,已经有一个包了,并且他的标题就是包名(package.json 文件的 name 字段), 描述就是 package.json 文件的 description 字段, 版本就是 1.0.0, 因为 author 字段是空,所以作者变成 Unknown.
如果有 README.md 文件的话,描述会优先获取 README.md 文件中主标题下的第一行,如果没有 README.md 文件的话,描述才会获取 package.json 文件的 description 字段
点进去会发现没有详情,也就是没有 README.md, 右边的详情也没有 author

所以接下来我们再迭代一个版本,因为是 patch 版本,所以新的版本号是 1.0.1, 然后填写了 author 这一栏,增加了 README 文件。1
2
3
4
5
6
7
8
9
10
11{
"name": "testlog",
"version": "1.0.1",
"description": "is test log",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "zach",
"license": "ISC"
}
再 publish 一次,可以看到版本号变成 1.0.1 了, author 信息有了, readme 内容也有了

每次发布的时候, version 字段都要往上加,不能往下,可以走最后一位修订号(patch),也可以是第二位的次版本号(minor),或者第一位的主版本号(major),反正就是不能往下,不然会报错。
注意事项
同时要注意,正常情况下,在 publish 的时候,npm 默认也会排除一些文件,不会将他们发布到包中。 比如过滤掉这些:1
2
3
4
5
6
7
8
9
10
11
12
13
14.*.swp
._*
.DS_Store
.git
.gitignore
.hg
.npmignore
.npmrc
.lock-wscript
.svn
.wafpickle-*
config.gypi
CVS
npm-debug.log
其他的剩余文件都会发布上去,如果需要排除其他文件,可以在.npmignore中配置。
同时如果你的包是需要构建的,只需要发布构建后的文件,src 目录不需要,那么就要在 package.json 指定 files 字段,将构建后的目录或者文件包含在 files 数组里面, 这样子 npm 在 publish 的时候,就会默认只发布 files 数组里面的文件。
package.json,README.md,CHANGELOG.md,LICENCE这几个文件不需要特意指定到 files 数组,也会自动包含, 除非手动强制在.npmignore中配置不要
4. 撤销已发布的包
撤销已发布的包在 Verdaccio 中是通过使用 npm unpublish 命令来完成的,格式为:1
npm unpublish [@scope/]pkg[@version] --registry http://43.139.27.159:4873
@scope/是可选的,仅在你撤销的包在特定作用域下时需要。pkg是你要撤销的包的名称。@version是你要撤销的包的版本。如果你想撤销所有版本,可以省略这部分。
对于本例来说,由于在初始化的时候,并没有针对这个包设定作用域,因此不需要填。想撤销刚才发布的 1.0.1 版本, 就可以:1
2\testlog> npm unpublish testlog@1.0.1 --registry http://43.139.27.159:4873/
- testlog@1.0.1
这时候 web 后台就只剩下 1.0.0 的版本了。
如果想整个包都撤掉,也就是删掉,不带版本号就行了,不过要加 -f 指令,表示强制删除,如果没有的话,会报错1
2
3\testlog> npm unpublish testlog -f --registry http://43.139.27.159:4873/
npm WARN using --force Recommended protections disabled.
- testlog
这时候整个包都被删掉了,web 后台看不到这个包了

5. 关于 scope 作用域
首先为啥会有 scope 的需求, 很简单,所有 npm 包都有一个名称。如果你要给自己的包,起一个有「寓意」的名字,会发现绝大多数单词/短语已被占用,即使没有真正的内容,这真是无可奈何的事儿。如何解决这一困境呢? 你可以发布带作用域/范围(scope)的包,通过 scope + pkg 的全名称来让你的包不会重复,并且便于组织识别。
事实上 npm 上面的 scope 其实代表的就是 org 组织
所以正常我们在使用私有库 lib 的时候,如果是自己自研的,那么会带上 scope, 这个是因为我们的私有库的 lib,一般包含 3 种类型的 lib:
- 团队内部自研的,这时候 scope 就会是我们自己定的组织名称, 比如组织名称叫 air, 那么内部自研的库,都应该是以 air 这个 scope 命名。当然如果你内部自研的库很多,还可以再细分,比如如果是 js 功能的库,那么 scope 就可以叫
air-js, 如果是组件库的,那么 scope 就可以叫air-component - 基于线上开源项目再进行二开自己维护的,这时候 scope 就是开源项目的 scope
- 之前线上有开源,有地址,但是后面不再维护,或者是很旧的找不到线上包的库,这时候我们就会 fork 一份到私有库,但是不进行二开需求,这时候 scope 就是 fork
因为刚才的测试项目被 unpublish 删掉了, 所以我们重新再创建一个具有 scope 的项目,通过 npm init --scope xxx 来指定项目初始化的 scope1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16$ mkdir testlog2
$ cd testlog2/
$ npm init --scope zachke -y
Wrote to \testlog2\package.json:
{
"name": "@zachke/testlog2",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
这时候我就建了一个 scope 为 zachke 的包了,包名为 testlog2
6. 安装私有包
那么怎么在项目中安装呢? 有几种方式,首先我们先创建一个项目,就一个简单的 node 项目,也不引用什么 vue 框架了:1
2
3$ mkdir my-project
$ cd my-project/
$ npm init -y
1. 命令行直接指定 registry 安装
接下来直接安装刚才的那个包:1
\my-project> npm install @zachke/testlog2 --registry http://43.139.27.159:4873/
这时候就可以再 package.json 看到这个包的依赖了

接下来直接引用这个包就可以了。 补上项目的 index.js 入口文件:1
2
3const { mylog } = require('@zachke/testlog2');
mylog("hello!!")
并且补上 script 运行指令 node index.js:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16{
"name": "my-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"@zachke/testlog2": "^1.0.0"
}
}
接下来就可以使用 npm 运行了:1
2
3
4
5
6\my-project> npm run start
> my-project@1.0.0 start
> node index.js
mylog: hello!!
可以看到这个项目已经运行起来了,并且我们的私有包有被成功引用。 不过这种情况的安装有个问题,他是依赖 lock 文件,如果是 npm 安装,那么就是依赖 package-lock.json 这个文件,也就是本地中的

如果是 yarn 安装的,那么就是依赖于 yarn.lock 文件。
这种方式的安装缺点就是一旦这个 lock 文件被删掉,那么就不会从私有源安装。因为外部公共 npmjs 没有这个私有包,就会报错。
2. 私有库设置为全局的源
第二种安装方式,就是将你的私有库的源设置为全局的源1
2
3npm config set registry http://43.139.27.159:4873
yarn config set registry http://43.139.27.159:4873
这样就可以使你的项目中的所有包都从私有源安装,Verdaccio 会自动代理 npmjs.org上的包 (可以指定 uplink 的其他代理),并且会缓存这些包以加快安装速度,但是可靠性未验证,暂时不推荐。
而且为了安全,其实我是推荐在私有库的配置中,将上游的 npm 的代理配置关闭的,也就是非私有库的包,不应该通过私有库地址去安装, 也就是将 packages 中的各个 scoped 的配置下面的 proxy 配置删掉或者注释掉1
2
3
4
5
6
7
8packages:
'@*/*':
# scoped packages
access: $all
publish: $authenticated
unpublish: $authenticated
# 既然是私有库了,找不到就需要去公网找,这样子更安全
# proxy: npmjs
一旦关闭了 proxy 功能,这时候安装包就更不能走将私有库设置为全局源的方式了,不然就会出现该项目安装其他非私有库的时候,就会找不到报错。
3. 项目配置中指定特定的registry为特定的scope提供包 (推荐)
本例就是在 my-project 项目下,创建一个 npm 包配置文件 .npmrc ,比如本项目就是 .npmrc, 然后在这个文件中指定特定包的特定源,比如本例就是
如果是 yarn 安装的,那么就是
.yarnrc文件

这边配 scope 就可以了,它会将所有这个 scope 中的包,全部换成后面指定的地址来下载,也就是我们的私有库地址。1
@zachke:registry=http://43.139.27.159:4873/
scope 如果不写的话,比如这样子1
registry=http://43.139.27.159:4873/
那其实就是全局配置了,是只针对这个项目的全局配置,本质上跟第二种全局改 registry 的效果一样。也不推荐,所以还是要有 scope
测试结果如下,先把原先的包删掉,然后再安装1
2\my-project> npm uninstall @zachke/testlog2 --registry http://43.139.27.159:4873/
\my-project> npm install @zachke/testlog2
而这个也是我们项目中最常用的安装私有库包的方式。
发布操作加钉钉通知
接下来我们给发布行为的操作,加上钉钉通知,Verdaccio 是支持 hook 触发的,具体看:
然后 config.yaml 文件中的最后配上,要记得重启 docker 容器生效 (docker restart verdaccio)1
2
3
4
5
6
7# notify
notify:
'dingding':
method: POST
headers: [{ 'Content-Type': 'application/json' }]
endpoint: https://oapi.dingtalk.com/robot/send?access_token=0427285b76cebabe510d14c294dba6738dcb5991515368e7293f16f9f0ba47a6
content: '{"msgtype":"markdown","markdown":{"title":"【{{ name }}】 版本更新","text":"> 新的包版本更新!!!<br> **包名**: {{ name }} <br> **版本**: {{publishedPackage}} <br> **发布者**: {{publisher.name}} <br> **查看详情**: [查看链接](http://43.139.27.159:4873/-/web/detail/{{ name }})","at":{"isAtAll":false}}}'
然后重新推送一个新的版本,这时候可以看到有 log 了 (可以通过 docker logs -f verdaccio 查看 log):1
2
3
4info --- auth/allow_action: access granted to: zachke
info --- zachke is allowed publish for @zachke/testlog2
http <-- 200, user: zachke(125.77.202.250), req: 'PUT /@zachke%2ftestlog2', bytes: 1496/0
info --- A notification has been shipped: {"msgtype":"markdown","markdown":{"title":"【@zachke/testlog2】 版本更新","text":"> 新的包版本更新!!!<br> **包名**: @zachke/testlog2 <br> **版本**: @zachke/testlog2@1.0.5 <br> **发布者**: zachke <br> **查看详情**: [查看链接](http://43.139.27.159:4873/-/web/detail/@zachke/testlog2)","at":{"isAtAll":false}}}
效果就是钉钉可以收到机器人通知了:

最佳实践
1. 修改 web ui
正常情况,我们不太需要修改 web 界面 ui,但是为了更好的定制化,一般我们只需要改几个值,比如 title, logo, primary_color 这三个值就够了
比如我在配置文件 config.yaml 改成1
2
3
4web:
title: zachNpm
logo: https://kebingzao.com/images/avatar.png
primary_color: '#67b7bf'
重启一下 docker 容器,就可以看到生效了

如果还想再彻底一点的,
favicon还是可以调整的,甚至加载的 js 都可以换,但是一般没啥必要
2. 不启用 package 的代理功能
上文其实有说过,其实 Verdaccio 是支持非常灵活的代理下载功能的,比如我可以在 unlinks 指定多个代理源:1
2
3
4
5
6
7
8
9
10uplinks:
npmjs:
url: https://registry.npmjs.org/
server2:
url: http://mirror.local.net/
timeout: 100ms
server3:
url: http://mirror2.local.net:9000/
baduplink:
url: http://localhost:55666/
然后在 package 配置那边针对不同的 scope 来指定不同的 proxy, 甚至同一个 scope 可以指定多个下载源1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16packages:
'my-company-*':
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: server3 npmjs
'@my-local-scope/*':
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: server2
'**':
access: $all
publish: $authenticated
unpublish: $authenticated
proxy: npmjs
但是为了安全,我是不建议在私有库的资源里面再去代理下载公网的包的,所以应该将 proxy 的配置去掉,私有库就只负责下载私有库里面的私有包就行了。
但是需要注意的一点就是,一旦关闭了私有库的 package 代理功能,但是在涉及到全局安装(-g)的时候,就要注意了,就会出现该包的第三方依赖无法安装。
解决这个问题需要在安装之前设置私有源地址 例如:全局安装@zach-js-library 这个 scope 下的包全局依赖之前,需要设置scope @zach-js-library 的源地址,可以通过以下命令设置:1
npm config set @zach-js-library:registry http://43.139.27.159:4873
接下来,再安装包到全局:1
npm install @zach-js-library/<package-name> -g
这样子就可以安装全局的私有库了。
3. nginx 代理 https
Verdaccio 是支持 tls 的 https 配置,但是我们一般还是用 nginx 来代理 https 请求,一方面是便于证书的管理,每年换证书的时候,统一换 nginx 的证书就够了,其他服务的证书不需要额外去换。
另一方面 nginx 对证书链和支持和校验也是非常成熟的,不用担心会因为证书链的验证问题,导致某些情况会出现 ssl 的链接错误。
所以应该这样子配置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30[root@test-server conf.d]# cat npm.foo.com.conf
server {
listen 80;
listen 443 ssl http2;
server_name npm.foo.com;
ssl_certificate ssl/foo.com.crt;
ssl_certificate_key ssl/foo.com.key;
ssl_session_timeout 5m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3;
#兼容低版本的TLSv1.0 1.1 版本加密
ssl_ciphers EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES128-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA128:DHE-RSA-AES128-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA128:ECDHE-RSA-AES128-SHA384:ECDHE-RSA-AES128-SHA128:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA384:AES128-GCM-SHA128:AES128-SHA128:AES128-SHA128:AES128-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4;
ssl_prefer_server_ciphers on;
access_log /var/log/nginx/npm.foo.com.access.log;
error_log /var/log/nginx/npm.foo.com.error.log;
location /{
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://127.0.0.1:4873/;
}
}
同时这边还要注意一个细节,就是要将 nginx post 的限制调大一点,在 nginx.conf 那边调整,1
client_max_body_size 10M;
调整跟 verdaccio 的默认配置值一样即可:
max_body_size: 10mb
不然就会出现发布的时候包过大,出现报错 413 的情况。
4. 遵循版本号语义化
在发布版本的时候,版本号一定要遵循语义化的规则,具体看: 语义化版本 2.0.0
版本格式分为三个格式: 版本格式:主版本号.次版本号.修订号(MAJOR.MINOR.PATCH),版本号递增规则如下:
- 主版本号:当你做了不兼容的 API 修改,
- 次版本号:当你做了向下兼容的功能性新增,
- 修订号:当你做了向下兼容的问题修正。
先行版本号及版本编译信息可以加到“主版本号.次版本号.修订号”的后面,作为延伸。
基本上的用法:
| 包迭代状态 | 阶段(Stage) | 版本号更新规则 | 范例 | 用途 |
|---|---|---|---|---|
| 第一次发布 | New product | 从 1.0.0 开始 | 1.0.0 | 第一次发布上传包 |
| bug 修改并且向下兼容 | Patch release | 增加修订号(patch) | 1.0.1 | bug 小修复 |
| 新功能增加并且向下兼容 | Minor release | 增加次版本号(Minor),并且将修订号重置为 0 | 1.1.0 | 新的功能出现,并且不影响现有旧版本应用 |
| 可能会有无法向下兼容 | Major release | 增加主版本号(Major)并且后面的次版本号和修订号都重置为 0 | 2.0.0 | 会有破环性更新,旧版本再不调整代码的情况下,可能无法应用 |
除了可以直接在 package.json 直接修改版本号之外,我们可以用 npm version xxx 的方式来更新版本号1
npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]
比如: 原來是 1.0.0,用 npm version minor 就会变成 1.1.0, 后面使用包的时候,可以使用 npm upgrade <package> 更新包版本
然后在安装包的时候,也有一些符号或者表达式来保证,你在更新的时候,不会一下子跨大版本更新,比如
~–> 只允许修订号版本迭代(如果有缺省值,缺省部分任意迭代),比如~1.2.3相当于>=1.2.3 <1.3.0,~1.2相当于>=1.2.0 < 1.3.0^–> 允许次版本号迭代,比如^1.2.3相当于>=1.2.3 <2.0.0,^1.x相当于>=1.0.0 <2.0.0<、<=、>、>=、=–> 指定版本范围,比如=1.2.7 <1.3.0中包括1.2.7、1.2.8、1.2.99等等,但不包括1.2.6、1.3.0或1.1.0等等x、X、*–> 可以替代主版本号.次版本号.修订号三段中任意一段,表示该位置版本号没有限制,*相当于>=0.0.0,表示任何版本号,1.X或1.x相当于>=1.0.0 <2.0.0,匹配到主版本号
总结
通过使用 verdaccio 搭建私有 npm 仓库,可以让前端的内部私有包得到规范的开发和流通,大大提供了前端开发的效率。
接下来说一下团队协作上的私有包的开发和发布规范: npm 私有库开发和发布规范
参考资料: