前言
组件库是一个老生常谈的话题,谈到公司基建,必然会涉及到组件库的搭建。虽然只要投入一定的人力和时间,似乎组件库的产出并不是一件难事,但是考虑到现在前端市场上有一定流行度的组件库的数量,还是屈指可数。由此可见,产出并不等同于优秀。因此如何在结合公司业务的同时,兼顾组件库的优秀设计和可用性是极其必要的。
背景
笔者所在的团队主要是做互动营销活动,基本上活动的类型是可以枚举出来的,当前的开发现状是:由于业务的特殊性,每个开发在做业务时不约而同的选择自己去开发对应的活动组件,而不是复用别人的,这样导致的结果是降低了开发效率和整个团队的产出,同时不利于推进业务模型和设计标准化,因此当务之急是建立一套抽象化的、高复用性和结合设计标准的业务模型组件库。
目标
- 支持Comonjs、EsModule等多种规范,提供全量注册和局部注册的能力;
- 包含一份可读性良好的文档说明,并且有示例可交互;
- 文档库、组件库发布自动化部署;
- 项目开发、提交、版本管理规范;
- 组件单元测试;
- 组件UI设计规范、API设计命名规范等;
- 组件开发者开发流程简单高效,不需要额外的心智负担。
起步
项目架构
技术选型
- 技术栈:vue >= 2.5.22 + tsx
- 包管理:vue-cli + yarn workspace
- 打包工具:rollup + babel
- 代码规范:stylelint + eslint + prettier
- 版本日志管理:standard-version + changelog
- 文档库:vuepress
- 单元测试:jest
开发流程
如何简化开发流程?
什么是好的开发模式,组件开发者只需要关注自己所开发的组件模块,包括组件源码、文档和demo都应该在当前组件文件模块下开发,整个工程内部负责拿对应的模块进行渲染,简化的方式如下:
- 组件的README.md文档,需要同步到`vuepress`工程目录下,才能实现文档的热更新,因此项目启动阶段,需要额外再启动一个文件复制的服务,实时监听.md文件的变更,拷贝到对应工程目录下;
- demo服务的路由直接根据组件demo文件进行注册,demo文件变更,对应的demo服务也会实时热更新。
编译打包
ts/tsx编译
通过`babel`核心库提供的`transformAsync`这个API进行编译即可,同时babel配置中加入一些预设`preset`,包含`preset-typescript`和`preset-jsx`两个预设。
less样式编译
利用less包自己提供的`render`函数就可以把less编译为css,不过还需要对css做进一步的自动浏览器前缀兼容处理,通过`postcss`插件即可实现。
vue单文件编译
一个vue文件包含一个`template`、`script`和多个`style`模块,因此需要对这些模块进行单独编译,由于在`webpack`中,所有的vue单文件都是通过`vue-loader`进行编译解析,所以考虑从loader中入手,包含以下几个API:
compileUtils
vueTemplateCompiler
复制代码
通过这些api可以拿到每个区块的源码,针对`script`模块的源码,需要编译为`render`函数,组装到对应的`render options`中去,`style`样式模块的源码,处理时需要考虑`scoped`特殊情况,编译时需要添加一个`scopedId`作为唯一的元素类名标识。
打包目标
需要支持`esModule`规范和`commonjs`规范,同时为了优化用户使用体验,需要做到按需引入和加载,也即`tree-shaking`的效果。
vuepress踩坑总结
问题1:vuepress默认主题不好看,如何自定义主题?
vuepress默认的主题不能满足所有开发者的需求,所以它提供了对外的自定义主题入口。只需要按照官方文档提供的约定主题的目录结构重新组织主题即可:
按照官方约定规范完成theme主题开发之后,vuepress会自动引用并渲染你开发的主题。
问题2:vuepress如何注册页面路由?
vuepress遵循“约定大于配置的原则”,根据docs所在的目录下的文件地址,自动注册页面路由地址,因此无需手动注册。
问题3:如何渲染markdown的内容?
vuepress提供了markdown插槽,对于一个markdown文件中的普通内容,会成为插槽的默认内容,你可以直接使用`Content`组件来访问它:
<Content />
复制代码
问题4:如何获取全局路由信息和自定义配置侧边栏页面路由的顺序?
-
vuepress在编译阶段,向开发者提供了全局的计算属性,包含站点数据page,路由信息就包含在其中;
-
vuepress的Markdown文件可以包含`YAML front matter`,同时必须作为文件中的第一部分,基本例子如下:
group: 基本组件
level: 1
页面中可以通过$frontmatter获取到该配置项,其中的`group`为当前页面所在分组名称,`level`是当前页面路由在所在分组的层级大小,通过这两个配置项数据就可以对初始化路由进行自定义排序。
问题5:如何在文档中引入demo案例的源码?
vuepress中的markdown文档支持导入代码段,规则如下:
<<< @/filepath
<<< @/filepath{highlightLines}
复制代码
其中的`filepath`为需要引入源码的目标文件的路径,`highlightLines`为高亮的代码行数。
同时为了支持只按需导入目标文件的部分代码,它支持`VS Code region`,即可以在文件路径后方的`#`紧接着提供一个自定义的区域名称(预设为snippet)
输入:
<<< @/../@vuepress/markdown/__tests__/fragments/snippet-with-region.js#snippet
复制代码
如果需要在同一个源文件中添加引入多个代码区块,需要在全局`config.js`增加markdown的配置项,配置如下:
问题6:vuepress启动的文档服务如何去加载vue-cli启动的demo服务
考虑到项目需要同时启动两个服务,必然两个服务的端口号不一致,所以必然产生跨域问题,因此考虑用`iframe`去加载demo服务。
问题7:文档服务和demo服务的路由同步问题如何解决?
情况1:点击文档服务的侧边导航栏路由,demo服务如何同步对应的组件案例页面路由?
方案:同步动态改变`iframe`的`src`地址。
情况2:点击demo服务的组件列表项,文档服务如何同步到对应的组件文档页面路由?
方案:通过`postMessage`进行跨域通讯,子窗口发送消息,父窗口监听`message`事件获取子窗口发送的路由数据,通过路由导航到指定的文档页面。
问题8:demo服务下的页面如何引用本地打包之后的组件源码?
考虑到使用者在使用我们开发的组件库时的引入模式,因此需要通过引入打包后的组件源码来验证打包后的源码的可用性。
通过`vue-cli`提供的webpack配置项`resolve/alias`来配置别名指向到打包之后的目录,同时需要在项目启动阶段,启动一个实时监听文件变化而编译的服务,确保引用的源码始终是最新的:
// 别名-用于引用打包之后的组件源码
const resolve = (dir) => path.join(__dirname, dir)resolve: {
alias: { "@tuia/market-ui": resolve("es") }}
// 组件内部
import { component } from '@tuia/market-ui'
复制代码
后记
未完待续,后续随着项目的进展,会持续更新`组件API设计规范`、`单元测试`和`自动化部署`相关的总结,敬请期待~~~