前端 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或者長按識別下方二維碼進入前端技術交流羣 ,暗號:寫代碼啦

每日一題,每週資源推薦,精彩博客推薦,工做、筆試、面試經驗交流解答,免費直播課,羣友輕分享... ,數不盡的福利免費送

相關文章
相關標籤/搜索