前端 UI组件化的一些思考

本文为王一蛋原创文章,首发于 前端学习指南css

最近公司推起了共用 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

在本文中,咱们主要使用 React 做为UI组件化的例子,将页面细分组件化是 React 的核心哲学,咱们能够很是方便的将本文中的理念引入其中。webpack

咱们先来看一个关于 UI 设计指南典型的例子,这是 Salesforce 的 UI 库 Lightning Design System,他给了很是详细的 UI 规则,各个产品的页面、组件应当如何被处理,很是值得咱们学习与借鉴。先来看一个 style guide 应当有些什么内容:git

  1. 文档 由你团队成员所写的,若是使用 React 你能够直接经过注释 Proptypes 的方法,经过 React-docgen 生成文档。
  2. 代码预览 你应当提供一个可让开发者实时调试代码的地方,使其余这些组件的使用者能够更好地理解各个props 。
  3. 使用实例 提供一些如何将其数据导入 UI 的实例代码,使其余开发者能够更快上手与他们的使用状况。
  4. 相容性 譬如怎样使用警告、载入信息等额外内容的规范,来提供用户相一致的体验。

那么,如何搭建一个组件库呢?为了回答这个问题咱们能够将其细分为以下几个小步骤:github

  1. 将总体的问题拆开成细目。
  2. 如何处理 CSS ?
  3. 如何将资源如变量,图标等公有化?
  4. 如何将其打包,便于使用?
  5. 开始从中获取收益!

首先,咱们现讲如何将问题拆解,咱们应当将页面上显示的一切看做是组件。也就是说每当你拿到设计师的稿件,第一件事应当就是讲页面上一切你所能看到的元素翻译成无数个小组件,这也是 React 的理念:复用组件。web

下一步,咱们再将小组件组合成为较大的组件。这里不得不提到 Brad Frost 所提出的 Atomic Design。它所阐述的理念与本文所要说的观点类似,即由“原子”组成“分子”,“分子”构成“组织”,从而造成模板,进而生成页面。看下这些例子,标签,输入,按钮各是一个“原子”,合在一块儿即成了一个“分子”。面试


其次, CSS 一直以来都是一个很是棘手的问题。咱们应当如何处理类名冲突?如何使用第三方库的 CSS 文件?如何保证与 CSS 文件不冲突?如何确保相互独立?对于这些问题如今已经有了很多解决方案。npm

David Wells 在演讲中提到的与咱们公司如今所使用的都是经过 PostCSS + CSS modules的解决方案。关于 CSS Modules 搭配 React 的用法,这里有个很好的例子:Modular CSS with React 。具体来讲能够见此用例:api

/* 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 的配置做为起始点。

啰啰嗦嗦写了这么多,但愿你们都能从中能收获些许。最后再安利一下 Hyo,也算是本身的第一个认真作的开源项目,但愿你们多多点星! | Demo点这里 | 文档点这里 |

加微信号: astak10或者长按识别下方二维码进入前端技术交流群 ,暗号:写代码啦

每日一题,每周资源推荐,精彩博客推荐,工做、笔试、面试经验交流解答,免费直播课,群友轻分享... ,数不尽的福利免费送

相关文章
相关标签/搜索