最近針對平常業務需求使用react封裝了一套[組件庫], 大概記錄下整個開發過程當中的心得。因爲篇幅緣由,在這裏只對開發過程當中比較糾結的選型和打包等進行討論,後續再對具體組件的封裝進行討論。
文章首發於 我的博客
咱們都知道,組件化的開發模式對於咱們的開發效率有着極大的提高,針對咱們平常使用的基本組件進行封裝,能夠大量的簡化咱們對於基本UI的關注度,讓咱們的工做聚焦在業務邏輯上,很好的分離業務與基礎UI的代碼,使得整個項目更有調理,這也是咱們要進行本組件庫開發的緣由。css
然而現有React開源組件有不少,像ant-design和material-ui等等,是否須要花費精力打造適合自身團隊的組件庫每每須要酌情考慮。咱們來看下我現有團隊及業務的幾個特色:前端
能夠看出,咱們擁有封裝本身組件的精力和基礎,而且擁有經過基礎組件封裝改變目前開發現狀的需求。因此,這件事情是咱們應該而且須要儘快完成的事情。node
針對組件庫的封裝,咱們首先面對的是技術選型以及方案的規劃。大概包括如下兩點:react
Webpack + React + Sasswebpack
因爲團隊現有的項目都是基於React+Redux進行開發的,那咱們選擇的開發語言無疑是React。git
針對css選擇,雖然如今針對組件化開發,比較流行CSS Modules
和CSS-IN-JS兩中模塊化解決方案,咱們更但願咱們的組件是可進行定製的。所以針對組件,咱們以Sass做爲預編譯語言,提搞效率和規範性。配合css-modules,咱們能夠很方便的進行鍼對實際需求進行樣式更改。例如咱們有一個Tab組件,咱們已經定義好了其通用的樣式:github
.tip-tab { border: 1px solid #ccc; } .tip-tab-item { border: 1px solid #ccc; &.active { border-color: red; } }
而在業務中,針對某一個需求,咱們須要針對Tab組件的樣式進行微調。讓其在激活(active)狀態下border-color是藍色的。你固然能夠說,咱們可讓咱們的組件暴露出一些props,針對這些修改進行配置,傳入不一樣的props對應不一樣的風格。可是咱們每每沒法知足全部的業務需求,不可能針對組件把各類樣式都封裝進去。針對這種方案,咱們採用css-modules爲其添加惟一的模塊樣式:web
<Tab styleName="unique-tab" />
針對該模塊,對其進行基本樣式的修改:npm
.unique-tab { :global { .tip-tab-item { border-color: #eee; &.active { border-color: blue; } } } }
這樣,針對該模塊的定製樣式,能很好的進行鍼對需求的樣式定製,同時不對全局樣式進行污染。json
針對項目圖標,計劃使用svg-sprite方案。可是因爲產品處於在不斷迭代的過程當中,新的圖標不斷在增長。目前咱們並不會對圖標統一進行打包,而是在每次進行組件打包的過程當中,從項目中導入全部的圖標。用如下方式進行引入:
import Icon from '@common/lib' import errorIcon from '@images/error.svg' <Icon link={errorIcon} />
其實更好的方式是針對全部的圖標進行統一打包,生成svg-spirte文件(具體原理能夠查詢svg-sprite,在此再也不贅述)。當咱們進行使用時,只需直接引用便可,避免每次都進行打包,減小webpack處理依賴的時間:
<Icon type="error" />
針對開發流程和規範,咱們遵循如下幾個原則:
爲了便於後續的擴展,咱們更但願整個組件庫徹底脫離於項目進行開發。保證組件庫僅對於最基本的組件進行封裝,將項目UI代碼與業務邏輯進行分離。
針對不一樣的模式下,咱們有不一樣的文件入口,針對開發模式,咱們啓動一個dev-server, 在裏面對組件進行基本的封裝,並進行調試。打包時,咱們只需對組件內容進行封裝,暴露統一的接口。在文檔中,咱們須要進行案例和說明的展現。因此咱們在利用webpack的特性進行各類環境的配置:
npm run dev // 開發 npm run test // 測試 npm run build // 構建 npm run styleguide // 文檔開發 npm run styleguide:build // 文檔打包
組件庫做爲項目的最小力度支持,咱們須要保證其最基本的渲染效率,所以咱們採用pure-render/autobind等對其進行基本的優化。React有不少優化方式,在此不進行贅述。
針對組件庫的打包,咱們以UMD格式對其進行打包。webpack能夠針對輸出進行格式設置:(引自cnode)
配置以下:
output: { path: config.build.assetsRoot, filename: utils.assetsPath('js/[name].js'), chunkFilename: utils.assetsPath('js/[id].js'), library: 'TipUi', libraryTarget: 'umd' }
很明顯,咱們封裝的是一個針對React的組件庫,並不該該把React引用進去。通常咱們能夠採用externals的方式對其進行處理。
在這裏, 咱們採用dll方式將其與其餘第三方依賴統一進行打包,並將manifest.json和三方依賴的輸出文件輸出到項目中去,在項目中也使用dllReference進行引用。避免在項目中使用到這些依賴時重複進行打包。
同時,因爲咱們的組件庫處於一個不斷維護的狀態。這就須要咱們維持好項目庫和項目之間的打包關係,具體的流程如圖所示:
在每次進行項目打包的時候,首先檢測UI庫是否有更新,若沒有更新,則直接進行打包。反之繼續檢測dll的依賴是否有變化,如有,則打包dll,不然直接打包組件庫內容。而後將輸出結果同步到項目中,再進行最終打包。
固然,以上的這些流程都是自動進行的。
一個完善的文檔對於一個組件庫是及其重要的,每一個組件有什麼樣的配置參數,擁有哪些事件回調,對應的Demo和展現效果。假設沒有這些,除了封裝組件的人,沒有人知道它該如何使用。可是寫文檔的過程每每是痛苦的,在這裏推薦幾個文檔生成庫,能夠極大的簡化文檔工做:
咱們使用的styleguidist, 能夠將md自動轉化爲文檔,支持在md內直接調用你封裝好的組件並進行展現,簡單好用。最後封裝的文檔大概長這樣:
其實封裝組件庫這種工做有不少的東西值得琢磨和鑽研,因爲篇幅緣由,在這裏只對開發過程當中比較糾結的選型和打包等進行討論,後續再對具體組件的封裝進行討論。在書寫的同時,不斷參考下ant design這種優秀的組件庫,能學到不少的東西。更深入的理解封裝組件的思想,是一個很好的過程。