在 React 大生態下,一個比較成熟的前端團隊,都會面對一個問題:如何提升團隊的開發效率?css
一個系統擁有大量的業務場景和業務代碼,類似的頁面和代碼層出不窮,如何管理和抽象這些類似的代碼和模塊,這確定是諸多團隊都會遇到的問題。 不斷的拷代碼?仍是抽象成 UI 組件或業務組件?顯而後者更高效。前端
那麼如今就面臨一個選擇:一是選擇 React 生態中已有的組件庫,例如 antDesign、Material-UI 等比較成熟的組件庫;二是團隊再開發一套屬於本身的組件庫。有贊前端團隊選擇了後者,產出並開源了 Zent ,Zent 提供了一整套基礎的 UI 組件以及經常使用的業務組件,目前咱們有 45+ 組件,這些組件都已經在有讚的各種 PC 業務中普遍使用。本文咱們就來聊一聊如何開發一套優秀的 React 組件庫以及一套完整組件庫的構成。vue
React 大環境裏面有不少優秀的 UI 組件庫,國內比較有名的 antDesign,國外的 Material-UI,都是比較穩定和優秀的組件庫。那麼咱們爲何還要本身去開發一套組件庫呢?緣由大體以下:node
Design
和 SKU
組件。構建一個完整的組件庫須要考慮:react
組件是對一些具備相同業務場景和交互模式代碼的抽象,組件庫首先應該保證各個組件的視覺風格和交互規範保持一致,X
組件在 A
業務場景是一個交互,在 B
業務場景是另外一個 UI 風格,這樣就沒法對 X
進行抽象,極大的增長了組件的構建成本。因此,設計組件之初,首先須要抽象和約定一套統一的視覺風格和交互規範。git
其次,組件庫的 props 定義須要具有足夠的可擴展性,並且組件內部徹底受控,保持組件具備統一的輸入和輸出,讓咱們來看一個 Button 的例子。es6
// Button is a react component of Zent
<Button
type="primary"
className="customer-classname"
loading={true}
disabled={false}
size="large"
onClick={this.handleClick}
>
{children}
</Button>
複製代碼
這是一個 Button 組件,咱們定義了不少標記狀態的 props,好比 type 表示 Button 的視覺風格,size 表示尺寸,disabled 禁用,loading 狀態等,這些狀態在組件內部都不會維護 state,全部的狀態由傳入的 props 來決定,自定義 className 方便咱們作樣式自定義,children 方便咱們自定義 Button 的顯示內容。github
Button 甚至提供了a
標籤的功能,只要在Button上傳入 props:href。markdown
// Button as <a>
<Button
type="primary"
className="customer-classname"
href="https://www.youzan.com"
target="_blank"
>
有贊首頁
</Button>
複製代碼
咱們須要作幾個約定:app
有贊前端內部組件庫,使用的是開源 lint 工具-- felint 。
felint 是一個集成了 eslint、stylelint、git hook 的前端代碼檢查工具。felint 爲你的項目作如下三件事:
具體使用能夠參考官方 doc -- felint 文檔地址 。
約定好組件的設計思路和代碼規範之後,接下來咱們就能夠參與開發組件了,組件庫的基本開發流程,包括如下幾點:
Zent 裏面有一個組件初始化命令:yarn new-component
,這個命令完成了組件大部分初始化工做,包括自動建立組件須要的目錄和模版代碼,添加組件 js 和 css 代碼。而後,咱們就能夠開始寫組件代碼,代碼風格和規範嚴格按照 lint 的規範編寫,若是不符合規範,是不能提交代碼的。寫完組件之後,須要寫組件 Demo 並運行,方式是本地啓動 server 來運行組件 Demo,這個能夠組件做爲組件的調試工具。
js 單元測試框架有不少,chai、jest、mocha、karma 等等,Zent 組件庫使用的是 jest + enzyme 的組合,下面來看一個例子:
// Button UI test import { mount } from 'enzyme'; describe('Button', () => { it('Button UI test', () => { const wrapper = mount(<Button>OK</Button>); expect(wrapper.hasClass('zent-btn')).toBe(true); expect(wrapper.text()).to.equal('OK'); }); }); 複製代碼
使用 jest 作 UI 測試有侷限性,只能測試基本的 dom 結構 和樣式,一些邏輯交互沒法測到,只能覆蓋大部分的狀況。 yarn test
用來執行測試腳本,測試結果會顯示在終端。
組件平常維護佔整個組件庫生命週期的很大一部分,組件庫作起來了之後,組件功能後續會不斷迭代,也許是 bug fix,也多是 new feature,這些組件的迭代咱們經過 PR 和 issue 來管理,同時,咱們須要管理好組件的 changelog。 總的來講,組件維護主要包括:PR / issue 的處理,發包和管理 changelog。
下面以 Zent 爲例,來介紹一下 PR 規範。
PR 標題規則:[ bug fix / breaking change / new feature ] 組件名字:修改內容描述
PR 用來生成 changelog,規範的 PR 有助於生成比較清晰的 changelog,一目瞭然,來看一下 Zent 的例子:
組件發包只有擁有發包權限的人才能操做,Zent 是以組件庫爲單位發包的,yarn build
會將整個 Zent 的代碼打包,使用命令 yarn publish
發包,在發包以前會跑組件測試,只有測試經過之後才能發包。
一份好的 doc 是一個優秀組件庫的標準,良好的文檔可以提高組件庫的總體品質和好感度,願意花時間好好寫 doc 的團隊,那麼他們產出的組件庫應該也不會差到哪去,組件庫文檔維護也是組件庫生命週期裏重要的一環,有時候你甚至須要作到中英文雙語 doc。
這裏附上 Zent 組件庫的 doc 地址:Zent。
在本文中,咱們從組件的設計思路、編碼規範、開發流程、測試、平常維護這五個方面闡述瞭如何構建一個 React 組件庫,而且以 Zent 爲例講述了有贊是如何作的,任何一個組件庫都須要的通過這個生命週期,但咱們須要思考的是:如何營造一個良好的組件庫生態環境? 咱們須要想辦法讓更多的人蔘與其中,共同做爲組件庫的維護者,選擇開源是爲了給 React 生態環境作輸出,在前端組件化已經成爲了既定事實的今天,咱們不須要重複的造輪子,而是須要在組件化方面嘗試新的突破,脫離前端技術的束縛,站在工程師的高度去抽象本身手頭的代碼。組件化這條路上,咱們還有不少事情要作,Zent 只是一個開始。