最近公司推起了共用 UI 组件化的大潮,创建了一个新的 Repo 来放置共用的 UI 组件,比如下拉菜单等。出于对历史版本的表单组件的不满,我从两周前开始踏上了自己的 React 表单组件制作之路,踩了不少坑也有了不少感悟,之后也会写一篇文章关于我是如何写这个组件的(对 React 感兴趣的可以点这里 Hyo ,中文文档)。之后公司群里分享了这么一个演讲视频:Best Practices on building a UI component library for your company (David Wells) - FSF 2016 ,看完之后感触良多,本文算是该演讲内容的一个梗概与探讨。
回到正题,如果你在一个大型团队工作,或者你的企业有许多部门,你们该如何实现全局 UI 组件来跨越各个板块的界限?想象一个场景,如果你的整个公司都在使用同一段 UI 代码处理公共组件,财务工具在使用它,博客工具在使用它,在线聊天工具在使用它,且无论是在移动端,桌面端还是 web 端都能见到它,那该有多便利?无需累赘而繁复地一遍又一遍实现功能类似的表单,按钮或是列表。这是一个相对理想的设置,因为无论你在哪儿你都只需要维护一个代码库,且所有全局资源也都在同一个地方,开发者们可以方便地找到所需的代码并对其贡献。同时,共享 UI 组件同事也会给你的用户带来相容的体验,无论他在浏览或使用哪个工具,移动端或是桌面端,他的所见所感都是相一致的。注意的是同步这一概念,对于拥有很多产品的公司来说如果共享 UI ,那就意味着一次 UI 升级整个公司的产品都会受其影响。这从大部分意义上来说是一件好事,但有时又会带来很多麻烦,之后会说到。同时你的组件也应当是完备的,不与任何你所在团队所使用的第三方包相冲突。综上,如何设计你团队产品的 UI 架构,使得其兼具上述优点的同时还有良好的可扩展性与性能,是我们今天所要讨论的重点。
在本文中,我们主要使用 React 作为UI组件化的例子,将页面细分组件化是 React 的核心哲学,我们可以非常方便的将本文中的理念引入其中。
我们先来看一个关于 UI 设计指南典型的例子,这是 Salesforce 的 UI 库 Lightning Design System,他给了非常详细的 UI 规则,各个产品的页面、组件应当如何被处理,非常值得我们学习与借鉴。先来看一个 style guide 应当有些什么内容:
那么,如何搭建一个组件库呢?为了回答这个问题我们可以将其细分为如下几个小步骤:
首先,我们现讲如何将问题拆解,我们应当将页面上显示的一切看作是组件。也就是说每当你拿到设计师的稿件,第一件事应当就是讲页面上一切你所能看到的元素翻译成无数个小组件,这也是 React 的理念:复用组件。
下一步,我们再将小组件组合成为较大的组件。这里不得不提到 Brad Frost 所提出的 Atomic Design。它所阐述的理念与本文所要说的观点相似,即由“原子”组成“分子”,“分子”构成“组织”,从而形成模板,进而生成页面。看下这些例子,标签,输入,按钮各是一个“原子”,合在一起即成了一个“分子”。
其次, CSS 一直以来都是一个非常棘手的问题。我们应当如何处理类名冲突?如何使用第三方库的 CSS 文件?如何保证与 CSS 文件不冲突?如何确保相互独立?对于这些问题现在已经有了不少解决方案。
David Wells 在演讲中提到的与我们公司现在所使用的都是通过 PostCSS + CSS modules的解决方案。关于 CSS Modules 搭配 React 的用法,这里有个很好的例子:Modular CSS with React 。具体来说可以见此用例:
/* Thumbnail.jsx */ import styles from './Thumbnail.css'; render() { return (<img className={styles.image}/>) } /* Thumbnail.css */ .image { border-radius: 3px; }
Hash 后生成的 HTML tag 与 CSS 看起来会是这样:
/* Rendered DOM */
<img class="Thumbnail__image___1DA66"/>
/* Processed Thumbnail.css */
.Thumbnail__image___1DA66 {
border-radius: 3px;
}
此处将在我们 Thumbnail.jsx 文件中通过 CSS modules 引入 CSS 文件,再通过引入的 style 变量获取 hash 后的 CSS 类名。
此处提到的另一个工具 PostCSS 会将你的css文件全加上前缀名以适应不同浏览器,解决 CSS 4 的兼容性问题。
所以你真的需要使用 PostCSS 和 CSS Modules 么?你可以问自己如下问题:你在一个团队中工作么?你使用第三方库的 CSS 文件么?你的产品在第三方环境中运行么?你想要你的产品在任何环境中体验一致么?如果你回答是,那你可以选择尝试这一方案,因为这一解决方案基本解决了类名冲突与浏览器兼容的问题。
第三,关于如何处理共享资源。对于全局变量与 mixin ,我们建议通过几个 PostCSS 的插件来解决,而非使用sass等预处理器语言。可以通过一个简单的Postcss config来解释:
var vars = require('postcss-simple-vars'); var mixins = require('postcss-mixins'); var postCSSConfig = [ mixins({ mixins: require('./mixins') }), vars({ variables: require('./variables') }), ]
此处我们从一个 mixins.js 文件中提取全局mixin,一个 varibles.js 文件中提取全局变量,他将会在你所有通过 PostCSS 编译的 CSS 文件中生效。实际使用中与less和sass十分相似,见例:
.hyo { @mixin MarsPower; /* 在 mixin.js 文件中定义 */ color: $MarsRed; /* 在 variables.js 文件中定义 */ }
对于图标,由于其轻量型与便利性我们一般选择 svg。基本的工作流程是由设计师制作 svg ,在你的 JS 代码中引入 svg ,通过 ’webpack-svgstore-plugin’ 优化 svg 并生成 sprite ,将 sprite 注入 DOM 。此处我们可以使用 svg use 标签,形式如:
<svg><use id=“icon-aaa”></svg>
第四步,也是最后一步,我们应当如何搭建以及打包?
首先,我们有非常多的工具来使得开发 React 组件变得令人心情愉悦,推荐几个常用的第三方库:
carte-blanche 这是个非常牛b的 React 开发工具,只需简单几步就可已在浏览器中测试你的 React 组件,同时还支持随机生成 prop 来测试你的组件会不会应为 prop 异常而崩溃。
react-storybook 这是一个 carte-blanche 非常相似的选择,也是我用来开发 Hyo 的工具。
react-docgen 文档生成工具,你可以直接导入一个react文件夹,如果你在proptype中谢了注释它将会自动为你生成文档。
在版本更新时,注意使用语义化版本。每当你要开始写一个新的组建时,可以先在 Github 上搜索一下前人的实现方法,站在巨人的肩膀上做事才会事半功倍。
最后,关于如何打包,DW 推荐的方法是如下文件结构:
对此我表示很赞同。分开打包每个小的组件入口,扁平化你的文件结构,组件之间可以相互依赖使用,对于开发效率与扩展化能力十分有帮助。
有些时候很难去查阅你在哪个页面使用了哪个组件。这里你可以使用一个监视器组件来查询你使用的组件。这在很多时候非常便利,譬如你想升级某一个组件,你会想去了解哪些页面或是组件依赖了这个组件从而进行修改,DW 提供了一个实现,我们可以根据我们的需求来实现自己的 Monitor Component。
最后的最后,小结几个开发 React 组件中常遇见的问题。(至少我是碰到了- -)首先,做之前想明白要实现的 Feature,与设计师讨论并写下自己的需求,市面上是否有可用的替代品,尽可能不要定义过多的 prop,不然在之后维护会非常辛苦。其次,尽可能地给予使用者客制化的权利,譬如内容如何渲染,排序如何进行等,最好开放一个 api 使得使用者可以自己定义,因为你永远无法预测并满足所有使用者的需求。第三,在所有浏览器上进行测试,老生常谈了但有时还是会忘。最后,从开始便定义好 lint 的规则并遵从它,可以参考 AirBnB 的配置作为起始点。
啰啰嗦嗦写了这么多,希望大家都能从中能收获些许。最近开了b站成为了一名up主,主要是分享一些程序员相关和我做Google工作的心得,希望大家关注一波多多支持,多谢大家
https://link.zhihu.com/?target=https%3A//space.bilibili.com/526143269
饥人谷一直致力于培养有灵魂的编程者,打造专业有爱的国内前端技术圈子。如造梦师一般帮助近千名不甘寂寞的追梦人把编程梦变为现实,他们以饥人谷为起点,足迹遍布包括facebook、阿里巴巴、百度、网易、京东、今日头条、大众美团、饿了么、ofo在内的国内外大小企业。 了解培训课程:加微信 xiedaimala03,官网:https://jirengu.com
本文作者:饥人谷方应杭老师