前言

最近做的專案使用了微前端框架single-spa。

對於這類微前端框架而言,通常有個utility應用,也就是公共應用,裡面是各個子應用之間可以共用的一些公共元件或者方法。

對於一個團隊而言,專案中公共元件和方法的使用難點不在於封裝不在於技術,很多時候在於團隊內部成員是否都能瞭解這些元件,以避免重複開發,從而提升團隊效率。

如果是團隊比較小,人員比較穩定的專案組可能還好點,對於團隊比較大,人員流動較快的團隊,這些通用元件和方法往往就被人遺忘在角落,很難再得到有效利用。

因為我所在的專案還在開發初期,並且是新入職也想去熟悉一下當前專案中的一些通用元件和方法,所以我自己特意開發了一個文件應用去解決這個問題。

技術方案選型

對於一個面向Ant Design程式設計的鹹魚而言,這個文件應用肯定是往這個方向做。

目標是能做成Ant Design的元件文件那樣好用,既能很快看清元件的使用效果,也能快速複製示例程式碼。

有了目標之後,很快選定了兩個技術方案

  • StoryBook方案
  • 自己開發解析markdown檔案的文件應用

StoryBook是市面上一款比較流行的構建UI元件和文件的庫,功能很強大。

但是這個庫如果要應用到我們專案的團隊存在以下問題:

  • 英文文件,有學習成本
  • 引入single-spa的utility應用很麻煩
  • 對於構建在utility應用中的元件,需要在StoryBook中再寫一遍,容易不同步
  • 對於通用方法可能不支援

尤其是第三點特別存在問題,團隊成員大都是業務開發,有交付壓力,不是在github上為愛發電的開源貢獻者。

他們是否有意願在utility應用中寫了一遍元件程式碼後,又專門跑到這個StoryBook中再寫一道?

如果元件程式碼修改後,StoryBook這邊沒修改,這種不同步很容易導致開發人員明明按照文件使用元件,但是元件就是報錯,挫敗感很強。

聯絡到現實,我已經預想到如果走這個方案,一個月內這個玩意就會名存實亡,成為形式主義的存在,在三個月後成為大家都不願提起的垃圾了。

所以有了第二個方案的誕生:自己開發解析markdown檔案的文件應用

這個方案並不是我憑空想象出來的,而是在前公司中就有這麼一個內部應用,元件開發人員自己編寫markdown檔案,最終生成元件文件,並且應用本身可以解析markdown檔案中的程式碼部分,從而在元件文件中生成對應的元件示例。

彼時我只是一個元件開發人員,並不是這個文件應用的實現人員,所以也不知道其技術原理。

但是前公司這個應用讓我知道了這麼玩行得通,當時作為元件開發人員,接受和使用這個應用異常輕鬆,只要會寫markdown就行了,沒有學習成本。而且使用這種方式,控制權掌握在自己手中,更容易和自己的團隊專案有效結合起來。

基本原理

雖然這個文件應用是我一個人花了兩天的時間獨立完成,但是花的是工作時間,完成後也是公司內部專案,所以這個文件應用我沒法開源出來。

不過我可以告訴大家一個主要思路和步驟,想必復現出來也並不困難。

第一步讓我們搞定這個專案的框架。

因為需要引入single-spa的utility應用,所以框架我直接用的是single-spa的基座,並且專案內含一個子應用用於展示文件。而utility應用直接引入線上開發環境的utility應用,避免團隊成員重複書寫元件程式碼,也解決了文件和實際應用不同步的問題。

通過這一步,我們解決了StoryBook方案中的痛點2和痛點3。

第二步我們需要載入markdown檔案。

這一步肯定是通過webpack的載入器來做處理,這些載入器有的比較強大,可以直接將markdown檔案轉換為html。但是我並沒有選擇這種,而是直接用的raw-loader,將我們的markdown檔案轉換為字串載入。

程式碼大致如下,這個比較簡單,就不說了。

module.exports = {
module: {
rules: [
{
test: /\.md$/,
use: 'raw-loader'
}
]
}
}

第三步我們需要解析markdown檔案生成文件,並解析其中的React元件,生成元件示例。

解析markdown檔案轉換為html文件,實際上有個比較強大的庫,叫Showdown

而我所用到的庫react-showdown則是對Showdown的進一步封裝,可以藉助一個react元件將markdown和包含在markdown檔案中的react元件渲染成html。

下面是它的一個官方示例:

import React from 'react';
import MarkdownView from 'react-showdown'; export default function App() {
const markdown = `
# Welcome to React Showdown :+1: To get started, edit the markdown in \`example/src/App.tsx\`. | Column 1 | Column 2 |
|----------|----------|
| A1 | B1 |
| A2 | B2 |
`; return (
<MarkdownView
markdown={markdown}
options={{ tables: true, emoji: true }}
/>
);
};

通過MarkdownView這個元件,可以將一串markdown格式的文字轉化為html。

另外我們注意到它的選項,tables為true,如果不設定這個的話,markdown中的table格式將不會被轉化成表格。第二個emoji為true是支援emoji轉換。

這個時候你可能要問,這只是轉換了一下markdown檔案而已,轉換react元件呢?

我們可以看一下下面這個官方示例:

import MarkdownView from 'react-showdown';

function CustomComponent({ name }: { name: string }) {
return <span>Hello {name}!</span>;
} const markdown = `
# 我是個標題: <CustomComponent name="world" />`; <MarkdownView markdown={markdown} components={{ CustomComponent }} />

在markdown文字中可以直接寫上CustomComponent這個自定義的react元件程式碼,然後在MarkdownView的components中傳入CustomComponent即可。

生成的最終html中不僅會有個標題,標題下面還會展示一個叫hello world!的文字,而不是展示<CustomComponent name="world" />這個字串。

排疑解難

看完了上面的原理,想必您已經可以實現這樣的一個文件應用了。

不過在這個過程中您可能還是會遇到一些小麻煩,這裡提前給您支個招。

麻煩1:markdown轉換成html後的程式碼高亮處理。

因為我們做的是一個元件文件,那麼肯定會涉及到程式碼展示。

markdown檔案中的程式碼塊,使用react-showndown轉換後的並沒有做高亮處理。

不過react-showdown是支援Showdown的各種擴充套件的,其中有個擴充套件叫showdown-highlight,通過這個擴充套件可以對程式碼塊做高亮處理。

麻煩2react-showndown只支援簡單的元件。

雖然react-showndown可以解析react元件程式碼,但是它也只能簡單解析這個元件。如果我們演示的示例比較複雜,涉及到一些函式,還有一些庫的引用,很顯然不能再markdown檔案中直接寫。

這裡我建議直接將每個元件的示例寫到一個獨立的js中,這個js匯出一個Demo元件,然後我們在markdown檔案中直接引用這個demo元件即可。

大致程式碼如下:

import MarkdownView from 'react-showdown';
import ButtonDemo from './ButtonDemo'; const markdown = `
# 按鈕元件 元件描述 ## 程式碼示例 <ButtonDemo /> ```tsx
這裡貼出以ButtonDemo元件中的程式碼
``` ## API | 屬性 | 說明 |XXX|
|----------|----------|-----|
| title | 按鈕文字 | XXX |
| type | 按鈕型別 | XXX | <ButtonDemo />`; <MarkdownView markdown={markdown} components={{ ButtonDemo }} />

通過上面這種方式,不論我們ButtonDemo中的邏輯和功能多麼複雜,展示出來都是沒問題的。

麻煩3:如何將這個文件應用做到簡單好用。

看了上面的程式碼,可能有人會覺得應該沒問題了。

但是我們得明白,我們這個東西是做給業務開發的人員用的,而不是做給我們自己用的。

我業務開發人員為什麼要知道你這些什麼 react-showdown 的程式碼?

我業務開發人員還要學習你的這些鬼東西?

不是每個人都想著學這些亂七八糟的技術好嗎?

我每天就只想在6點下班,就算你5分鐘內給我講明白了,你這個文件應用我用不用還兩說。

你要是5分鐘之內還講不明白怎麼用,那你休想我在這上面給一個公共元件寫文件。

我們面對的基本就是這麼一個場景,我們做這個應用是為了解決專案中實際面臨的問題,是面向業務開發人員程式設計,而不是面向領導和KPI程式設計。

所以我們需要做到簡單好用,將所有涉及到react-showdown這玩意的部分全部不被業務開發人員感知。

想象一下,寫一個元件的文件,縮減到最少,就是一個markdown檔案,和一個demo.js。

那麼我們就只讓業務開發人員去寫這兩個東西就行,把他們的工作量減少到最小。

就給他們兩個資料夾,一個資料夾叫doc,裡面放markdown檔案,一個資料夾叫demo,裡面放各個demo。

再用一個字典配置dict.js,去做個基本的配置。

如果現在有個元件叫Easy要寫文件,那麼我們的dict.js內容可能就是下面這樣:

const dict=['Easy','Hard','XXX']

export defalt dict

只需要加個字串Easy即可。

然後你可以在那麼doc資料夾下加個markdown檔案叫EasyMD.md,demo資料夾下加個檔案叫EasyDemo.tsx。

之後的所有步驟全部由我們的文件應用解析dict.js後自動完成,無需使用者操心。

通過這樣的一種約定,我們可以將業務開發人員的工作量減到最小,把他們寫元件文件的門檻降到最低。

具體程式碼實現就略過了,實現的關鍵詞叫:import()函式,其他的不用多說了。

總結

雖然說這個文件應用是受前公司啟發,而且因為開發時間就兩天,所以比較簡陋,但是至少我做到了比前公司的內部應用更簡單方便,完全沒有學習成本。

好了,自吹一波就得了,本篇部落格到此結束。

如有疏漏之處,還請不吝賜教。