这是我参与8月更文挑战的第3天,活动详情查看:8月更文挑战
1. 整体架构
前两天我们已经搭建好了 npm 私有库,但光是有私库是不够的,考虑到私库需要迭代,也需要提供使用说明,因此我们还需要一个存放私库源码的仓库。这个仓库用于维护私库的基础信息,使用方法,在线 demo,同时它也应该具备有发布到 npm 私有库的功能。
基于以上考虑,我们的前端资源仓库整体架构如下:
2. 源码架构设计
从上图来看,我们已经解决了 npm 私有库的问题,对于组件库的整体架构设计而言,核心问题是组件库的代码是如何组织和管理。
业界一般会把同一类组件库用单个仓库的形式维护,并且把组件开发成 NPM 包的形式。这里的重点是,你要考虑把所有的组件打包成一个大的 NPM 包,还是分割是一个个独立的小 NPM 包 。 这两种选择会使仓库的目录结构有不小的差异,进一步又会影响到后面组件的开发,构建,发布。
单包架构
如果你选择把所有的组件看成一个整体,一起打包发布,这叫做单包架构。单个仓库,单个包,统一维护统一管理,比如 antd。
优点
- 可以通过相对路径实现组件与组件的引用,公共代码之间的引用。
缺点
- 组件完全耦合在了一起,必须把它作为一个整体统一发包。
PS:选择使用单包架构的话,那么必须提供按需加载的能力,以降低使用者的成本。
多包架构
多包架构的每个组件彼此独立,单独打包发布,单个仓库多个包,统一维护单独管理。
优点
- 组件发布灵活,支持按需使用。
缺点
- 组件与组件之间物理隔离。对于相互依赖,公共代码,只能通过 NPM 包引用的方式来实现。
在前端领域,我们使用第三方库 Lerna 来维护这样的架构,Lerna 针对包之间有依赖的场景做了一些特殊优化,开发模式下,它会把所有存在依赖关系的包通过软链的形式连在一起,就可以很方便的本地开发联调。
如何区分是单包还是多包架构
每个组件都没有 package.json,不能单独发布到 npm,每次改动都需要一起打包发布,也不能单独下载,这个是单包架构。
每个组件都有 package.json,可以单独发布到 npm,这个是多包架构。
3. 基于 Lerna 的多包管理架构
经过考虑,我们的组件库基础框架是基于【Lerna】的多包管理架构。Lerna 是一个管理工具,用于管理包含多个软件包(package)的 JavaScript 项目。
基于 Lerna 的多包管理架构的优点在于:
- 组件级别解耦,独立版本控制,每个组件都有版本记录可追溯
- 组件单独发布,支持灰度、版本回滚以及平滑升降级
- 按需引用,用户安装具体某个组件包,无需配置即可实现按需加载的效果
- 关注点分离,降低大型复杂度、组件之间依赖清晰且可控制
- 单一职责原则,降低开源基友的参与和贡献难度
Lerna 安装和使用教程
1. 安装和初始化
全局安装
npm install -g lerna
初始化 lerna,会在项目根目录下添加 lerna.json 配置文件。
lerna init -i // -i 独立模式,包版本单独管理
2. Lerna 常规命令使用
安装依赖
// 安装所有 packages 的依赖项并且连接本地包的交叉依赖项
lerna bootstrap
// 将各包中相同的依赖提取到根 node_modules, 最好先 lerna clean 删除各包依赖
lerna bootstrap --hoist
删除依赖
// 删除所有 packages 下的 node_modules,不会删除 root 目录的 node_modules
lerna clean
// 删除指定包下面的 node_modules
lerna clean --scope=<package-name>
创建 package(也可以在packages目录下手动创建)
// -y 通过lerna 快速创建
lerna create <packageName> -y
安装依赖
// 将本地或者远程的包作为依赖项添加到当前的packages中,每次只能添加一个包;
// 如果使用 workspaces,各个包都安装一遍
lerna add axios
// 安装到指定的包中,--scope 指定需要安装的包名
lerna add axios --scope=<package-name>
使用 import 命令导入本地包
lerna import <path-to-external-repository>
发布到 npm,发布包到npm需要登录,可以通过npm whoami查看当前登录用户,通过npm login进行登录。
lerna publish
4. 开发 npm 包
Lerna 是管理包和包之间的关系的工具,在基础框架搭建起来之后,就进入到组件库的开发流程中。为避免篇幅过长,这部分明天开一个单章简述。