你還在為元件文件煩惱嗎?

Samon發表於2022-07-05

前言

隨著時間的推進,業務元件也逐漸豐富起來,我們開始搭建元件庫,編寫元件文件的煩惱就隨之而來。

這裡分享下我選取元件文件工具的經歷,最終以 Docusaurus 為基礎,搭建了一套開箱即用的 React 元件文件工具。

此工具經過了兩年時間的沉澱也是比較穩定,所以分享出來給有需要的人員使用,直接體驗可看 react-doc-starter 這個專案。

元件庫文件工具的對比

從 0 到 1 搭建一個全新的元件庫文件工具不是最優的選擇,本人先在網上搜尋一些已有的解決方案。
業務專案技術棧是基於 React,UI 庫使用的是 Antd,下面是一些方案的彙總和分析:

  • bisheng,Antd 官網是基於 bisheng 改造的,Antd 官網看起來是很不錯,但是基於 bisheng,是需要做很多定製化的處理,不能開箱即用,上手難度相對大。
  • Gitbook,大家基本都瞭解,gitbook2 還支援 github 線上讀取生成,但是無法支援元件 demo 的展示。
  • Gatsby,擁有豐富的外掛生態,但是學習成本較高,更適合搭建門戶類的網站。
  • VuePress,Vue 官方文件使用的文件工具,開箱即用,簡單使用,但是不是 React 技術棧。
  • Docz,基於 Gatsby,開箱即用,支援 mdx,是一款比較適合的元件文件工具。
  • Docusaurus,開箱即用,是 facebook 團隊推出的,支援 mdx,也適合搭建 React 元件文件,create-react-app 目前的官方文件是使用 Docusaurus。

工具選取的曲折之路

Docz 的嘗試

2020 年初的時候,選取了 Docz,因為 Docz 開箱即用,支援 mdx 語法,提供便捷的 Props 和 Playgroud 元件。

Props 元件可讀取元件的註釋生成 API,Playgroud 元件可以在 mdx 檔案中執行 Demo 元件,同時可以檢視執行的程式碼,例子如下:

---
name: Button
route: /
---
​
import { Playground, Props } from 'docz'
import { Button } from './'
​
# Button
​
<Props of={Button} />
​
## Basic usage
​
<Playground>
  <Button>Click me</Button>
  <Button kind="secondary">Click me</Button>
</Playground>

經過一番折騰之後,借鑑 Antd 官網的樣式,效果如下:

image-20220628145052723.png

使用 Docz 後遇到的一些問題

你以為這樣就解決了元件文件上的問題嗎?並沒有,隨著元件的增加,文件的變多,docz 開發啟動時間和打包時間越來越長,甚至達到了 5 分鐘以上。

5 分鐘如果是首次那也能勉強接受,但是新建一個檔案,服務出錯,又需要重新啟動服務,然後等待。。。

後來元件開發由 JavaScript 轉 TypeScript,雖然 Docz 官方是支援 TypeScript,但是嘗試遷移過去的時候,發現比較耗時間。

使用 Docz 遇到以下問題:

  • 元件文件變多之後,服務啟動和打包時間有點久,開發效率有影響
  • 文件遷移 TypeScript 的成本相對高,除開 Demo 和 md 檔案可大部分複用,文件工具基本需要從頭再來。
  • 不支援類庫模式的文件快捷生成
  • Playground 元件中程式碼無法使用獨立檔案

    import { Playground } from 'docz'
    import { Counter } from './Counter'
    ​
    # Counter
    ​
    <Playground>
      {() => {
        const [counter, setCounter] = React.useState(0)
        return (
          <Counter
            value={counter}
            onChange={() => setCounter(counter => counter+1)}
          />
        )
      }}
    </Playground>

Docz 的代替方案 docusaurus

2020 年初的時候,選取了 Docz,也沒留意到 Docusaurus。後來 Docz 啟動服務開發文件的時間越來越久,同時決定由 JavaScript 轉 TypeScript,2020 年中旬本人開始尋找 Docz 的代替方案。

經過多方的查詢,並沒有找到合適的可代替 Docz 的方案。最終 Docusaurus 進入了我的視線, 經過深入瞭解,Docusaurus 使用相對簡單(個人理解就是 React 界的 VuePress), 支援 mdx,同時擁有強大的可擴充性。

但是 Docusaurus 並不支援類似 Docz 的 Props 和 Playground 元件,不支援便捷生成 API ,也不能同時展示 Demo 元件效果和程式碼,還需要經過一些處理才能達類似 Docz 用法的效果。

對 Docz 的 Playground 和 Props 元件思考

首先看下 Docz 的 Playground 和 Props 元件的使用方式:

---
name: Alert
menu: Components
---
​
import { Playground, Props } from 'docz'
import { Alert } from './Alert'
​
# Alert
​
## Properties
​
<Props of={Alert} />
​
## Basic usage
​
<Playground>
  <Alert>Some message</Alert>
</Playground>
​
## Using different kinds
​
<Playground>
  <Alert kind="info">Some message</Alert>
  <Alert kind="positive">Some message</Alert>
  <Alert kind="negative">Some message</Alert>
  <Alert kind="warning">Some message</Alert>
</Playground>
​

鑑於上面的使用方式,有兩點思考:

  • 能不能直接使用 Playground 和 Props 元件,而無需 import ?
  • Playground 能不能通過路徑引用 Demo 檔案來實現展示元件效果和程式碼?

其實是可以的,通過 webpack loader 的方式,本人實現了 PropsTableCodeShow 兩個元件(其實可以理解為 jsx 的語法糖),下面介紹下這兩個元件。

PropsTable 元件
<PropsTable src="$components/Table" showDescriptionOnSummary />

PropsTable 預設只讀取 export default 的元件註釋,註釋規則需要滿足 react-docgen 的註釋方式,詳細的例子可看 react-doc-starter 這個專案。

效果如下圖所示:

image-20220701192418716.png

CodeShow 元件
<CodeShow file="$demo/ProContent/Basic.tsx" />
<CodeShow fileList={['$demo/ProContent/Basic.tsx', '$demo/ProContent/Basic.module.less']} />

之所以不叫 Playground 是因為 CodeShow 元件不支援動態修改程式碼,同時 CodeShow 元件還支援多檔案的程式碼展示(例子的渲染只渲染第一個檔案的程式碼),詳細的例子可看 react-doc-starter 這個專案。

效果如下圖所示:

image-20220701193741368.png

那類庫的文件呢,繼續手寫 markdown?

實現了 PropsTableCodeShow 其實已經基本滿足了 React 元件文件的快速編寫需求。

但是業務上也有一些 Utils(工具函式) 的沉澱,如果要同時在 React 元件文件工具中編寫,則需要按照原始的 markdown 寫法來實現,無法直接讀取註釋,效率會相對低。

所以本人又開始在網上找尋了生產類庫文件的解決方案,最終微軟的 tsdoc 進入了我的視線,通過 tsdoc 獲取註釋資料,然後結合 babel-parser 解析出來的 AST 元件 props 資料,最終實現了可在 mdx 使用的 TsDoc 元件。

<TsDoc src="$utils/createFullscreen" />

效果如下圖所示:

image-20220705162755873.png

image-20220705163050311.png

實現 Demo 跳轉 CodeSandbox

Demo 在 CodeSandbox 中執行是錦上添花的,可有可無,也沒有特別複雜。

CodeSandbox 的原理就是通過檔案的文字生成 URL 字串引數,開啟 URL 後引數中的字串會還原成檔案結構和內容。

雖然是不復雜,但是還是踩了一些坑:

  • 由於 create-react-app-typescript 不支援 less module 的用法, 使用 craco 來快捷支援此功能,卻發現怎麼都無法支援 less module 的功能。本人猜 CodeSandbox 內部本來就做了一些模板的支援,配置 craco 無效。
  • 使用 vite 支援 less module,功能是實現了,但是開啟的時候,需要執行終端安裝依賴包(相對慢點),而且線上修改程式碼不能立即生效,重新整理頁面大部分情況下也會重新安裝依賴包。總的來說就是執行速度相對慢。

最終還是放棄了支援 less module 的功能,採用 create-react-app-typescript 模板,然後使用原始的 css 功能實現 demo 的功能。

最終效果

直接體驗可看點選這裡

image-20220705170131948.png

後續的一些想法

react-doc-starter 目前基於 docusaurus 實現的文件工具適合基於第三方元件的業務元件文件,如果是像 Antd 這類自研的元件,則需要而外適配一套 UI presets 來替換 @docusaurus/preset-classic,如果有時間本人也打算實現一套 Antd 官網的主題出來。

react-doc-starter 目前 PropsTable 也只能讀取預設匯出的元件,其他 ts interface 的註釋還不支援讀取,後續可能會使用 typedoc 來實現。

相關文章