前端工程化之 npm 私服

使用 Verdaccio 快速搭建私有 npm 仓库

程化系列的上篇文章讲到了组件的发布及使用,这篇文章就来看看如何高效搭建易用私有组件仓库

组件有跨项目共用的需求,也就要考虑到组件代码的存储和传播了,排除了 Bit 后满足这两点的最适宜内部组件存储的介质就是 npm 私有仓库了,它具有以下几个特质:

  • 安全性:只有内网可访问,避免代码泄露
  • 复用性:与 npm 公共库一样便于下载传播
  • 版本管理:统一管理组件库版本,语义化版本号

再综合考虑其它因素如搭建复杂度、框架量级、业务场景,我们选择了使用 Verdaccio 来搭建公共组件仓库。

Verdaccio 介绍

Verdaccio 是一个基于 Node.js 的轻量化私有 npm proxy registry,proxy registry 对应的便是 npm 官方的 public registry,具体概念见 registry | npm。简而言之,Verdaccio 的本质作用是管理发布上来的 npm 包,并且使之与官方包隔离,易用性主要体现在这些地方:

  • 配置方式简单
  • 权限控制清晰
  • 开箱即用的 Web 界面

搭建组件仓库

安装 Verdaccio

私有的组件仓库要能被其他开发人员访问,就要放在服务器上了。确保服务器安装好 Node 环境后,全局安装 Verdaccio:

1
$ npm install -g verdaccio

安装好后终端输入 verdaccio 即可启动服务,由于 Verdaccio 是一个 Node 服务,会随着终端关闭终止服务,可使用 PM2 管理:

1
2
3
4
$ pm2 start verdaccio # 启动服务
$ pm2 list            # 查看服务列表
$ pm2 log <id>        # 查看日志
$ pm2 stop <id>       # 关闭服务

成功启动服务后 log 中会显示四条主要信息:

1
2
3
4
warn --- config file  - /root/.config/verdaccio/config.yaml      # 配置文件位置
warn --- Plugin successfully loaded: verdaccio-htpasswd          # 鉴权插件
warn --- Plugin successfully loaded: verdaccio-audit             # 审核依赖插件
warn --- http address - http://localhost:4873/ - verdaccio/5.0.1 # 服务入口

此时浏览器访问服务器的 4873 端口(云服务器需确保在安全组开启该端口)可进入私有仓库的 Web 界面,当然了,目前还是比较简陋的。

配置 Verdaccio

Web 界面、插件、权限等配置都在启动时日志显示的配置文件中修改,编辑该文件为:

 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
# /root/.config/verdaccio/config.yaml

# 数据的存储位置
storage: /root/.local/share/verdaccio/storage
# 插件目录位置
plugins: ./plugins

# web 界面配置
web:
  # 网页标题
  title: Verdaccio
  favicon: https://xuezenghui.com/favicon.ico
  # web 界面语言
  i18n:
    web: zh-CN

auth:
  htpasswd:
    # 存储用户认证信息的文件地址
    file: ./htpasswd
    # 最大用户数,设为-1表示不允许自行注册
    max_users: 100

# 私有仓库没有找到包时的查找路径
uplinks:
  npmjs:
    url: https://registry.npmjs.org/

packages:
  '**':
    access: $all
    publish: $authenticated
    proxy: npmjs

server:
  keepAliveTimeout: 60

middlewares:
  audit:
    enabled: true

logs:
  - { type: stdout, format: pretty, level: http }

初始化组件仓库

接下来需要将上次封装好的组件发布到配置好的私有 npm 仓库中,具体步骤:

1. 本地注册 Verdaccio 用户

本地注册用户需执行 $ npm adduser --registry <IP 地址:4873> 并按提示输入用户名、密码和邮箱,完成后可在 Web 界面进行登陆查看仓库内容,也才能在本地发布/使用私有的 npm 包。

但我们不能允许任何人都可以注册用户,所以通常需要设置配置文件中的 max_users 属性为 -1 禁止自行注册,需要注册时可使用官方工具 Htpasswd Generator 创建密钥信息,由管理员添加进htpasswd文件中,避免反复打开/关闭配置文件中的属性。

2. 项目文件及配置

先给公共组件项目创建软件包的代码仓库 lib 目录,创建 lib/components.js 文件来处理仓库中的 Vue 组件,文件内容与 src/utils/global.js 基本一致:

要注意的是lib目录里不能使用别名导入文件,比如表示 src 目录的 @,需替换成相对路径。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import Vue from 'vue';
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context('../src/components', true, /\.vue$/);

requireComponent.keys().forEach(fileName => {
  const componentConfig = requireComponent(fileName);
  
  const componentName = upperFirst(camelCase(fileName.split('/').pop().replace(/\.\w+$/, '')));

  Vue.component(`Z${componentName}`, componentConfig.default || componentConfig)
});

将 Vuetify 配置一并导出,确保仓库中的组件与组件仓库里穿着同样的「衣服👔」:

 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
import Vue from 'vue';
import Vuetify from 'vuetify/lib';
import '@mdi/font/css/materialdesignicons.css'
import '@/assets/sass/main.scss'

Vue.use(Vuetify);

const theme = {
  primary: '#6DA4D8',
  secondary: '#FDDB55',
  error: '#EF3A61',
  success: '#51AD5A',
  info: '#6DA4D8'
};

export const options = {
  theme: {
    themes: {
      dark: theme,
      light: theme,
    },
  },
  icons: {
    iconfont: 'mdi'
  }
}

export default new Vuetify(options);

创建包的入口文件 lib/main.js,引入样式和所有组件:

1
2
import '../src/assets/sass/main.scss';
import './components';

然后在package.json文件中设置好包名name、版本号version等描述信息,添加main指定包的入口文件,添加files指定库中包含的文件目录,并修改属性privatefalse保证包可被发布,这部分与 npm 发布包一致,参考 package.json | npm Docs

1
2
3
4
5
6
7
+- "private": false,
++ "main": "lib/main.js",
++ "files": [
++     "lib",
++     "src/assets",
++     "src/components"
++   ]

3. 发布公共组件

指定 register 地址发布包到私有仓库:

1
$ npm publish --registry <IP 地址>

发布成功后会显示包的一些元数据:

publish.webp◎ 发布成功

访问 Web 界面可看到包的基本信息:

web.webp◎ Web 界面


当然了,组件库应该设置一定的读写权限来控制包的使用和发布权限,Verdaccio 中包的使用权限逻辑默认是这样的:

如果你配置了账户,那么你就能登入 Web 界面查看库中软件包的详细信息,有了包名和 registry 地址,你就能安装使用了。也就是说,有无账户体现在对包的可见性

权限在配置文件的packages下添加:

1
2
3
4
5
6
packages:
  'my-components':
    # 使用权限
    access: $authenticated
    # 发布权限
    publish: zander

权限设为 $all 表示任何人对这个包有相关权限,$authenticated表示只有经过验证的有权限,此处发布权限设为了固定的用户,在进行 publish 操作时 Verdaccio 会根据用户注册时自动生成的authToken(可通过$ npm config ls -l命令查看)进行鉴权。

使用公共组件

OK,至此,NPM 私服就已经搭建完成了,而后其它项目中便可以像使用普通 npm 包一样简单地使用企业内部公共组件了,先安装组件 npm 包:

1
$ npm install my-components --registry <IP 地址> -D

本案例中使用了 Vuetify 组件库,因此使用公共组件的项目中要正确显示组件样式需确保安装完整 Vuetify 的相关依赖,推荐使用 $ vue add vuetify

最后,在 src/main.js 中引入组件:

1
import 'my-components';

Now, enjoy your components in the global Vue!

1
<z-btn large color="yellow">🎉🎉</z-btn>

结语

这篇文章拖了挺久的,学习和再总结的过程花费了不少时间,但工程化相关的探索似乎才刚刚开始,也如我所说,在项目迭代、人员变动等影响因素下去实际运用抽离的组件,推动团队的组件化进程才是步履维艰的。

组件管理也应有一个合理的流程,协调好 UI 设计者、组件开发者、测试者和使用者等参与人员的流程关系同样重要,我总结了一个组件定义的流程图,我们团队目前在遵循此流程:

flow.png◎ 共用组件定义流程

另,本文涉及的代码位于我的 GitHub:

updatedupdated2021-04-282021-04-28
fix: 字句修改
加载评论
点击刷新