前端 UI組件化的一些思考

最近公司推起了共用 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 應當有些什麼內容:

  1. 文檔 由你團隊成員所寫的,如果使用 React 你可以直接通過注釋 Proptypes 的方法,通過 React-docgen 生成文檔。

  2. 代碼預覽 你應當提供一個可以讓開發者實時調試代碼的地方,使其他這些組件的使用者可以更好地理解各個props 。
  3. 使用實例 提供一些如何將其數據導入 UI 的實例代碼,使其他開發者可以更快上手與他們的使用情況。

  4. 相容性 譬如怎樣使用警告、載入信息等額外內容的規範,來提供用戶相一致的體驗。

那麼,如何搭建一個組件庫呢?為了回答這個問題我們可以將其細分為如下幾個小步驟:

  1. 將整體的問題拆開成細目。

  2. 如何處理 CSS ?

  3. 如何將資源如變數,圖標等公有化?

  4. 如何將其打包,便於使用?

  5. 開始從中獲取收益!

首先,我們現講如何將問題拆解,我們應當將頁面上顯示的一切看作是組件。也就是說每當你拿到設計師的稿件,第一件事應當就是講頁面上一切你所能看到的元素翻譯成無數個小組件,這也是 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 的配置作為起始點。

啰啰嗦嗦寫了這麼多,希望大家都能從中能收穫些許。最後再安利一下 Hyo,也算是自己的第一個認真做的開源項目,希望大家多多點星! | Demo點這裡 | 文檔點這裡 |
推薦閱讀:

在React.js中使用PureComponent的重要性和使用方式
koa 實現 react-view 原理
react 行,我等你

TAG:前端开发 | 前端工程师 | React |