漫談 React 元件庫開發(二):元件庫最佳實踐

有贊技術發表於2019-02-16

在 React 大生態下,一個比較成熟的前端團隊,都會面對一個問題:如何提高團隊的開發效率?

一個系統擁有大量的業務場景和業務程式碼,相似的頁面和程式碼層出不窮,如何管理和抽象這些相似的程式碼和模組,這肯定是諸多團隊都會遇到的問題。 不斷的拷程式碼?還是抽象成 UI 元件或業務元件?顯然後者更高效。

那麼現在就面臨一個選擇:一是選擇 React 生態中已有的元件庫,例如 antDesign、Material-UI 等比較成熟的元件庫;二是團隊再開發一套屬於自己的元件庫。有贊前端團隊選擇了後者,產出並開源了 Zent ,Zent 提供了一整套基礎的 UI 元件以及常用的業務元件,目前我們有 45+ 元件,這些元件都已經在有讚的各類 PC 業務中廣泛使用。本文我們就來聊一聊如何開發一套優秀的 React 元件庫以及一套完整元件庫的構成。

一、選擇開源?還是自己造輪子?

React 大環境裡面有很多優秀的 UI 元件庫,國內比較有名的 antDesign,國外的 Material-UI,都是比較穩定和優秀的元件庫。那麼我們為什麼還要自己去開發一套元件庫呢?原因大致如下:

  • 有贊各個業務線 PC 產品有獨立的設計規範,包括但不限於元件樣式、互動模式。
  • 有贊微商城、零售、美業等 PC 產品的業務場景較為複雜,需要深度定製某些通用的元件,如 DesignSKU 元件。
  • 需要同時支撐有贊多個業務部門的 PC 產品。
  • 團隊成員以開源的模式參與元件庫的開發,期間會有很多互相的討論、碰撞,本身也是對團隊的鍛鍊過程。

二、元件庫構成

構建一個完整的元件庫需要考慮:

  • 元件設計思路
  • 元件程式碼規範
  • 元件開發流程
  • 元件測試
  • 元件維護(包括 PR / issue 管理、發包、文件)

1. 元件設計思路

元件是對一些具有相同業務場景和互動模式程式碼的抽象,元件庫首先應該保證各個元件的視覺風格和互動規範保持一致,X 元件在 A 業務場景是一個互動,在 B 業務場景是另一個 UI 風格,這樣就無法對 X 進行抽象,極大的增加了元件的構建成本。所以,設計元件之初,首先需要抽象和約定一套統一的視覺風格和互動規範。

其次,元件庫的 props 定義需要具備足夠的可擴充套件性,而且元件內部完全受控,保持元件具有統一的輸入和輸出,讓我們來看一個 Button 的例子。

// 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 的顯示內容。

Button 甚至提供了a標籤的功能,只要在Button上傳入 props:href。

// Button as <a>
<Button
  type="primary"
  className="customer-classname"
  href="https://www.youzan.com"
  target="_blank"
>
  有贊首頁
</Button>
複製程式碼

我們需要做幾個約定:

  • 元件所有狀態受控於 props
  • 元件 children 支援自定義 Dom 結構
  • 不要寫死元件內部的 Dom 結構

2. 元件程式碼規範

有贊前端內部元件庫,使用的是開源 lint 工具-- felint

felint 是一個整合了 eslint、stylelint、git hook 的前端程式碼檢查工具。felint 為你的專案做以下三件事:

  1. 初始化 eslint/stylelint 配置檔案,無論是 react 專案、vue 專案、es5 還是 es6 都提供了針對性的配置方案
  2. 安裝 eslint/stylelint 及其依賴到當前專案的 node_modules 裡
  3. 掛載 git 鉤子,在你提交程式碼時進行強制校驗

具體使用可以參考官方 doc -- felint 文件地址

3. 元件開發流程

約定好元件的設計思路和程式碼規範以後,接下來我們就可以參與開發元件了,元件庫的基本開發流程,包括以下幾點:

  • 元件初始化
  • 元件 Coding
  • 元件 Demo

Zent 裡面有一個元件初始化命令:yarn new-component,這個命令完成了元件大部分初始化工作,包括自動建立元件需要的目錄和模版程式碼,新增元件 js 和 css 程式碼。然後,我們就可以開始寫元件程式碼,程式碼風格和規範嚴格按照 lint 的規範編寫,如果不符合規範,是不能提交程式碼的。寫完元件以後,需要寫元件 Demo 並執行,方式是本地啟動 server 來執行元件 Demo,這個可以元件作為元件的除錯工具。

4. 元件測試

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 用來執行測試指令碼,測試結果會顯示在終端。

5. 元件維護

元件日常維護佔整個元件庫生命週期的很大一部分,元件庫做起來了以後,元件功能後續會不斷迭代,也許是 bug fix,也可能是 new feature,這些元件的迭代我們通過 PR 和 issue 來管理,同時,我們需要管理好元件的 changelog。 總的來說,元件維護主要包括:PR / issue 的處理,發包和管理 changelog。

下面以 Zent 為例,來介紹一下 PR 規範。

PR 標題規則:[ bug fix / breaking change / new feature ] 元件名字:修改內容描述

  • 前面方括號用來區分 PR / issue 的型別:bug fix - 元件 bug 修復;breaking change - 不相容的改動;new feature - 新功能
  • 修改內容儘可能言簡意賅,總結 PR 的改動或者描述 issue
  • 描述請用中文
  • 元件名字請用英文,首字母大寫

PR 用來生成 changelog,規範的 PR 有助於生成比較清晰的 changelog,一目瞭然,來看一下 Zent 的例子:

zent-components

元件發包

元件發包只有擁有發包許可權的人才能操作,Zent 是以元件庫為單位發包的,yarn build 會將整個 Zent 的程式碼打包,使用命令 yarn publish 發包,在發包之前會跑元件測試,只有測試通過以後才能發包。

元件文件

一份好的 doc 是一個優秀元件庫的標準,良好的文件能夠提升元件庫的整體品質和好感度,願意花時間好好寫 doc 的團隊,那麼他們產出的元件庫應該也不會差到哪去,元件庫文件維護也是元件庫生命週期裡重要的一環,有時候你甚至需要做到中英文雙語 doc。

這裡附上 Zent 元件庫的 doc 地址:Zent

三、小結

在本文中,我們從元件的設計思路、編碼規範、開發流程、測試、日常維護這五個方面闡述瞭如何構建一個 React 元件庫,並且以 Zent 為例講述了有贊是如何做的,任何一個元件庫都需要的經過這個生命週期,但我們需要思考的是:如何營造一個良好的元件庫生態環境? 我們需要想辦法讓更多的人蔘與其中,共同作為元件庫的維護者,選擇開源是為了給 React 生態環境做輸出,在前端元件化已經成為了既定事實的今天,我們不需要重複的造輪子,而是需要在元件化方面嘗試新的突破,脫離前端技術的束縛,站在工程師的高度去抽象自己手頭的程式碼。元件化這條路上,我們還有很多事情要做,Zent 只是一個開始。

漫談 React 元件庫開發(二):元件庫最佳實踐

相關文章