组件复用进化史
Ctrl C & Ctrl V
总听见有人戏谑的讲出 Ctrl C & Ctrl V 大法好
,并自称为“搬砖工程师”——殊不知这 CV
大法,其实是最朴素而原始的组件源码级复用方式
朴素,意味着这是一种集:
- 0 学习成本、0 技术壁垒
- 任意 Repo 复用
- 任意粒度复用
- Writeable
优点一身的利器;而因为原始,又充斥着够痛的槽点:
- 缺少 VCS
- 缺少依赖管理
后来, CV
大法进化的一种折衷形态是——把各种可复用的 Utils、Widget 代码放【拷贝、打包】到专门的 Repo、Asset 里,比如 CDN 上的 jQuery、支持选择下载的 Tangram——选择性的解决了一些槽点,也丢失了一些优点
Node Module
NodeJS 的时代,彻底被颠覆的前端生态——组件复用的高级形态 Node Module
我不确定,有多少的 Utils、Widget 组件直接一开始就是单独的 Repo——其实可能更多的组件,最初是和业务 Repo A 在一起, 而凑巧的是在 Repo B 里也能用上这些组件
在 npm 的时代,可能就需要需要 XV
【Ctrl X & Ctrl V
】,从 Repo A 到单独的 Node Module Repo,然后再 Repo A、Repo B 里通过 npm 引入任意的 Node Module VCS
其中优点:
- 文件粒度复用
- VCS
- 依赖管理完备
- 学习成本较低
槽点:
- 需要专门拆分 Repo【假定组件皆源于业务】
- Readonly
Git Submodule
Submodule 能将多个 Repo 形式上整合在一个 Repo——一种原始形态的类 Monorepo、直接复用源码的方式;等效的,还有更原始、却更方便的 ln -s
软链接
其显著的优点:
- VCS
- Writeable
其明显的槽点:
- 需要拆分多个 Repo
- 有一定学习和操作成本
Monorepo
Node Module 生态下的 Monorepo 是真正意义上的把多 Repo 合并成一个 Repo
其优势:
- Node Module
- 1 个 Repo
- Repo 内 Writeable
Monorepo 集成了所有的优势,尤其适合维护多个源码层面彼此相关,功能却又比较独立、完整的 Node Module 或者业务 Module,对应的技术方案有,如适合维护 Mono Node Module 的 Lerna,以及 Mono Business Module 的 NX 等
痛点:
- VCS 提交记录会变得比较复杂——如果仅为了组件复用,整合业务 Repo,成本收益 可能还不如使用 Submodule
- Monorepo 以外 Readonly,本质上依旧是 Node Module
- Monorepo 管理 Module 的成本还是比较高的,本质还是一个个 Node Module,需要对应的依赖、版本管理
- 比较高的学习、维护成本
- 此外,不是所有 Module 都适合放在同一个 Monorepo
bit 适用场景
经过客观的回顾【主观的踩】后,终于切入正题《什么场景适用 bit》——为了不那么具有攻击性和胁迫意味,我把主题从《为什么使用 bit》给改了过来
本质
初识者,往往会 bit、git 傻傻不分,除去 bit 最小存储单位、象征组件细粒度的本身含义,官方在在命名上肯定也有故意撞车 git 之嫌
bit 在 Repo 之上添加了文件到组件映射的语义层,构成了一套独立的类似 git 的 VCS
本地,默认情况下,在 .git 目录下会有一个 .bit 目录存储;远端的 bit server 其实就是依赖于 git 实现的
关键特性-优点
- 可直接从已有项目、库内导出组件
- 可在任意使用到组件的应用修改组件源代码
- 可以将组件的定制修改直接回馈给源组件
- 自动将组件包裹成 Node Module
- 细粒度
适应场景举例
1. 直接组件复用
设想在 Recruit Repo 里有维护一个符合 bit 组件规范 方的 Avatar 组件,然后再新开的 Admin Repo 里也需要用到这样一个 UI 一致的 Avatar 组件,比如这样:
然后:
- 2020 了,还要
Ctrl C & Ctrl V
??? - 拆分一个单独的 Node Module【Repo】 ???
- 把 Recruit Repo 和 Admin Repo 放一个 Monorepo ???
这么一对比,最适合的办法居然还是 CV
——
这样的场景,可以使用 bit 来更优雅的解决:
在 Recruit Repo 里,添加并导出 Avatar 组件,bit 会自动处理依赖、将 Avatar 组件包装成一个 Node Module
bit init
bit add avatar
bit tag
...
bit export
在 Admin Repo 里,通过 bit 引入 Avatar 组件,bit 会自动以 npm + ln 的形式,把 Avatar 组件安装到 node_modules 下,跟其他普通的 node module 没有本质的区别
bit init
...
bit import avatar
2. 需要定制修改
当 Admin Repo 需要一个圆形的、但是源组件是方形的 Avatar 组件,同时兼顾 Admin Repo 同步Recruit Repo 内变动的能力
这样似乎就只有 CV
可供选择,兼顾定制化与可人工同步变动的能力——
这样的场景,可以使用 bit 来更优雅的解决:
在 Admin Repo 里,引入 Avatar 组件——源码,进行任意的修改,并将改动提交到 Admin Repo 的 VCS
bit import avatar
改吧改吧
git add ...
并当 Recruit Repo 导出 Avatar 组件的新版本的时候,通过 bit 同步并合并变动
bit import avatar --merge
更多见 bit 工作流
3. 需要将改动分享到源组件
Admin Repo 同学发现并修复了 Avatar 组件的一个 bug,这个时候:
- 是告诉 Recruit Repo 同学如何手动再修复一遍这个 bug???
- 还是 Admin Repo 同学给 REcruit Repo 提一个 pr ???
除了源 Recruit Repo,如果还有 X1 Repo、X2 Repo 也用到了 Avatar 组件,无论人工同步修复,还是 pr,好像都不是那么顺畅——
这样的场景,可以使用 bit 来更优雅的解决:
在 Admin Repo 以及其他任意消费 Avatar 组件的 Repo【不要将组件添加到 Repo 的 VCS】,可以修复 bug、新增 feature 到 Avatar 组件,然后通过 bit 发布新的版本,并推送到远端 bit server
改吧改吧
bit tag
bit export
在 Recruit Repo 里,通过 bit 同步来自 Avatar 组件消费者的变动
bit import --merge
更多见 bit 工作流
4. 细粒度与 MonoRepo
设想,有维护一个专门组件库 Antd Repo,就像 antd 那样一个 node module 包含了几十个组件,这样可以很省事的开发、维护——
但大块头也有以下明显的痛点:
- 只能几十个组件整体发布
- 整体安装
- 整体引用——为了按需打包,还专门写了一个 babel-import-plugin
为此,我们会首选引入 Monorepo,比如说 lerna,来解决这些痛点——大块头的痛点确实也被解决了,几十个组件被拆成 Monorepo 里几十个独立的 packages,这项浩瀚的工程,虽然可以通过 CLI 命令行减少一些模板性质的重复劳动,但依赖管理、文件结构改造依旧是很繁琐的【从零开始的 Repo 不会繁琐的改造,繁琐的日积月累反倒不像一个真正的问题】
这里 MonoRepo 的痛点并不那么明显,bit 未必就能更优雅一些——比如 lerna 和 bit 都有较高的学习成本、相似的操作成本,唯一 bit 占优的地方就是:
- 因为 bit 已经承包依赖管理,可以不用那么关注组件的依赖,尤其组件相互的依赖
- 不再要求 node module 标准的目录结构
用与不用的选择
凡事有两面,工具也有两面,bit 推出的时间不算短,但其实一直使用的人并不太多,处于不温不火的局面
bit 的痛点:
- 学习心智,bit、git 傻傻不清,“雷同”的 CLI 命令偏偏还有些微的差异,很容易混淆【我司内部的 KBit 可以了解一下,NodeJS 层对 bit 进行了比较友好的封装】
- 操作成本,bit 已然算是独立 VCS、package manager 体系,所以在 git、npm 之外会有额外的操作成本
bit 当然是能解决实际应用的中的痛点,但这个痛点是不是够痛、是不是有还可以将就用的办法,可能就是决定用与不同的选择依据了
以上文字,以个人的直观经历和思考汇总而得,如有谬误欠妥之处,恭请指正