<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          干貨 | 從0到1,搭建一個(gè)體系完善的前端React組件庫(kù)

          共 5026字,需瀏覽 11分鐘

           ·

          2021-03-26 08:40

          作者簡(jiǎn)介

           

          劍橋,攜程資深前端開(kāi)發(fā)工程師,關(guān)注自動(dòng)化工具開(kāi)發(fā)、前端工程自動(dòng)構(gòu)建相關(guān)技術(shù)。


          隨著前端工程的發(fā)展,組件化的思想早已深入人心;現(xiàn)代的前端框架React/Vue等,都是圍繞組件設(shè)計(jì);組件化的開(kāi)發(fā)模式,大大提高了開(kāi)發(fā)效率;設(shè)計(jì)和開(kāi)發(fā)高質(zhì)量高復(fù)用性的公共組件,可以更好地保持產(chǎn)品迭代的高效和穩(wěn)定。


          我們以React的技術(shù)棧為背景,在日常的需求與迭代中, 歷時(shí)兩年多時(shí)間,沉淀出了攜程用車(chē)各大產(chǎn)線(接送機(jī)/包車(chē)/打車(chē)服務(wù)等)的公共組件(機(jī)場(chǎng)、航班、城市、地址、時(shí)間控件等)。通過(guò)持續(xù)交付了一系列的組件庫(kù),讓各個(gè)產(chǎn)線的開(kāi)發(fā)小組不用再各自維護(hù)重復(fù)而難以迭代的代碼,完成了前端組件與公共方法的收口,解決了用車(chē)前端業(yè)務(wù)組件一致性的問(wèn)題。同時(shí)隨著組件庫(kù)工作流上的逐步完善,讓前端開(kāi)發(fā)同學(xué)脫離了刀耕火種的開(kāi)發(fā)方式,進(jìn)入了全新的自動(dòng)化構(gòu)建與高效開(kāi)發(fā)的時(shí)代。


          開(kāi)發(fā)和維護(hù)一個(gè)可持續(xù)迭代的組件庫(kù),從來(lái)都不是一件容易的事情。本文將從組件庫(kù)的基礎(chǔ)搭建開(kāi)始,從開(kāi)發(fā)、打包、發(fā)布、拆包、優(yōu)化、自動(dòng)化測(cè)試等各方面,由淺及深地進(jìn)行介紹,給大家分享一個(gè)相對(duì)完善的組件庫(kù)落地的過(guò)程。同時(shí)也會(huì)介紹組件庫(kù)的迭代過(guò)程中真正會(huì)遇到哪些問(wèn)題,以及我們是如何解決這些問(wèn)題的。希望這些實(shí)戰(zhàn)中的經(jīng)驗(yàn),可以帶給大家一些啟發(fā)和想法。
           

          一、實(shí)現(xiàn)最基礎(chǔ)的npm發(fā)布流程


           
          在組件庫(kù)的設(shè)計(jì)之初,我們最先需要考慮的是,如何讓npm包的發(fā)布流程安全、可靠可行。為了保證代碼的安全性,公司內(nèi)部會(huì)獨(dú)立維護(hù)內(nèi)網(wǎng)的npm管理平臺(tái)。


          在最早的發(fā)布設(shè)計(jì)中,我們?nèi)匀煌ㄟ^(guò)官方定義的cli命令,在本地通過(guò)設(shè)置registry指向內(nèi)網(wǎng)倉(cāng)庫(kù)后,執(zhí)行npm publish 進(jìn)行發(fā)布。

          可是對(duì)于公司內(nèi)部而言,平臺(tái)開(kāi)放而B(niǎo)U眾多,任何人都可以對(duì)任何已發(fā)布的包進(jìn)行常規(guī)操作,這會(huì)帶來(lái)一系列的不安全因素。最終在前端委員會(huì)的推動(dòng)下,我司實(shí)現(xiàn)了內(nèi)網(wǎng)npm與gitlab ci的關(guān)聯(lián)。將發(fā)布操作遷移到了gitlab上,在發(fā)布權(quán)限上有一定的約束;通過(guò)開(kāi)啟npm deploy插件,以實(shí)現(xiàn)可視化交互式的發(fā)布管理,同時(shí)得益于gitlab hook的強(qiáng)大, 我們更是在流程實(shí)現(xiàn)了push event來(lái)觸發(fā)auto publish,這一系列的進(jìn)步,讓我們的組件庫(kù)在后續(xù)的發(fā)布流程上變得更加正式、穩(wěn)定而可靠。


          Npm關(guān)聯(lián)gitlab后,通過(guò)指定指定分支下特定目錄的package.json,實(shí)現(xiàn)版本升級(jí)后自動(dòng)發(fā)布
           

          二、組件庫(kù)的打包處理


           
          我們的技術(shù)棧涉及ReactWeb 與 React Native, 對(duì)于RN的代碼,我們一般會(huì)走源碼直接發(fā)布,RN項(xiàng)目中的編譯過(guò)程會(huì)自動(dòng)處理node_modules里的源文件。但是對(duì)于Web組件庫(kù)而言,更傳統(tǒng)的做法,則是需要在發(fā)布之前進(jìn)行一些編譯和轉(zhuǎn)碼,這樣才能確保發(fā)布之后的npm包,可以在大多數(shù)環(huán)境下正常運(yùn)行起來(lái)。

          對(duì)于Web端組件庫(kù)的打包,我們進(jìn)行了多次的探索和優(yōu)化。

          使用webpack對(duì)每個(gè)組件進(jìn)行單獨(dú)打包,打包類型由umd改為commonjs2。

          module.exports = {    output: {        filename: '[name].js',        path: path.resolve(__dirname, '..', 'dist'),        library: 'Tha',        libraryTarget: 'commonjs2' // umd    }}

          通常我們對(duì)組件庫(kù)的建議是umd打包,因?yàn)檫@樣可以實(shí)現(xiàn)多種模塊方案的加載通用性。但在實(shí)踐過(guò)程中發(fā)現(xiàn),每個(gè)組件都需要單獨(dú)打包時(shí),UMD的打包方式,會(huì)顯著增大每個(gè)文件的基礎(chǔ)體積;而且我們99% 的場(chǎng)景下,其實(shí)已經(jīng)并不用再去兼容AMD、CMD等模塊加載方式。

          在確保我們的代碼一定是通過(guò)node模塊方式加載的時(shí)候,我們只需要打出commonjs2的模塊即可。這一步的調(diào)整,顯著地提升了打包速度,也明顯減小了各個(gè)文件的打包體積。

          進(jìn)一步編譯優(yōu)化

          對(duì)于組件庫(kù)而言,使用webpack進(jìn)行打包,即使是使用了commonjs2的模式,繁重的配置工具仍然是顯得重了一些,而且需要額外配置各種external規(guī)則,以防止打包時(shí)打入了額外的第三方庫(kù)的代碼。使用rollup來(lái)處理組件庫(kù)的打包固然比webpack要合適,但是又會(huì)額外引入新的構(gòu)建工具,增加學(xué)習(xí)成本。

          最終我們選擇的更優(yōu)化的方案,是使用babel 直接做編譯轉(zhuǎn)換,不使用任何額外的構(gòu)建工具,也不做壓縮優(yōu)化處理---- 這些工作,在現(xiàn)代化的前端項(xiàng)目中,都會(huì)自動(dòng)處理,不需要組件庫(kù)再做多余的構(gòu)建動(dòng)作。Babel直接轉(zhuǎn)碼的方式,幫助我們省去了很多復(fù)雜的配置工作,并且讓組件庫(kù)打出來(lái)的生產(chǎn)代碼更加容易調(diào)試。

          優(yōu)化前,使用webpack等構(gòu)建工具打包組件:


          {  "scripts": {    "build:components": "webpack --config ./build/webpack.config.js --color",    "build": "npm run build:components && npm run build:css && npm run copy_package"  }}


          優(yōu)化后, 編寫(xiě)腳本直接對(duì)組件源文件轉(zhuǎn)碼


          {  "scripts": {    "build:components": "cross-env NODE_ENV=production node ./build/trans"  }}

          提取組件中的樣式文件,單獨(dú)打包

          Css-in-js的開(kāi)發(fā)方式固然是方便許多,但是在打正式包時(shí),內(nèi)嵌的css實(shí)際會(huì)占用更多的代碼體積,并且node_modules里的js代碼中如果有顯式require css的語(yǔ)句時(shí),在同構(gòu)項(xiàng)目中,可能會(huì)遇到服務(wù)端解析css文件的各種問(wèn)題。

          為了解決這個(gè)問(wèn)題,我們提取了所有組件的css進(jìn)行單獨(dú)打包。其中所有的基礎(chǔ)組件樣式,會(huì)整體打包成一個(gè)main.css;而復(fù)雜業(yè)務(wù)組件的樣式,則會(huì)以組件為單位進(jìn)行單獨(dú)打包,以便實(shí)現(xiàn)后續(xù)流程中業(yè)務(wù)組件的按需加載。


           

          三、組件庫(kù)實(shí)現(xiàn)業(yè)務(wù)組件的按需加載



          與各大知名的開(kāi)源組件庫(kù)類似,為了減少項(xiàng)目的打包體積,我們對(duì)組件庫(kù)中的復(fù)雜業(yè)務(wù)組件,如航班組件、機(jī)場(chǎng)組件、城市選擇組件等,設(shè)計(jì)了按需加載的模式。

          對(duì)RN而言,我們直接利用了require的特性,通過(guò)修改導(dǎo)出對(duì)象的get方法,顯式地聲明了lazyLoad的組件程式。

          module.exports = {    //按需動(dòng)態(tài)加載的模塊    get AddressList() { return require('./Address/List').default; }};

          對(duì)于Web而言,我們采用了類似ant-design的方式,在前面對(duì)業(yè)務(wù)組件的css進(jìn)行單獨(dú)打包處理后,通過(guò)在項(xiàng)目中引入babel插件的方式,實(shí)現(xiàn)組件的按需加載。

          import { Address } from '@ctrip/thanos-ctrip-mobile/components.biz'/** 等價(jià)于import Address from '@ctrip/thanos-ctrip-mobile/components.biz/Address'import '@ctrip/thanos-ctrip-mobile/components.biz/Address/style.css'*/

          四、解決組件庫(kù)日漸臃腫問(wèn)題


           
          隨著組件庫(kù)的不斷迭代,組件代碼會(huì)不斷增多,需求也會(huì)越來(lái)越復(fù)雜。其他研發(fā)同學(xué)也可能會(huì)開(kāi)發(fā)獨(dú)立的npm組件包,但是會(huì)基于已開(kāi)發(fā)完成的組件庫(kù)的部分功能來(lái)實(shí)現(xiàn)。

          這種情況下,開(kāi)發(fā)其他npm包的同學(xué),可能只想使用當(dāng)前已有庫(kù)中的部分功能,而不太愿意引入一個(gè)完整而龐大的組件庫(kù)。為了使組件庫(kù)的功能更加獨(dú)立且通用,讓UI組件與功能模塊之間更好地解耦,我們需要對(duì)組件庫(kù)進(jìn)行拆子包處理。

          如組件項(xiàng)目中基礎(chǔ)UI部分,從組件庫(kù)中剝離,拆分成獨(dú)立的ui-basic組件庫(kù);組件項(xiàng)目中工具方法(表單校驗(yàn)、環(huán)境判斷、正則處理、時(shí)間日期格式化等),拆分成獨(dú)立的 util庫(kù)。這種拆分組件包的開(kāi)發(fā)形式,組件庫(kù)不再是所有功能都揉在一個(gè)倉(cāng)庫(kù)中,開(kāi)發(fā)和維護(hù)將變得更加靈活且易于擴(kuò)展。

          拆包前,core的部分將隨著功能的增加而越來(lái)越臃腫:



          拆包后的結(jié)構(gòu):



          如圖所示,拆分獨(dú)立功能包后,可以讓我們擴(kuò)展和組合出更多靈活多樣的組件庫(kù),讓組件庫(kù)不再單一而臃腫。
           

          五、解決子組件包的開(kāi)發(fā)環(huán)境問(wèn)題


           
          拆分子組件包后,給組件庫(kù)的多樣性擴(kuò)展帶來(lái)了極大的便利,但隨之而來(lái)的問(wèn)題便是,每一個(gè)子組件包都需要單獨(dú)維護(hù),在開(kāi)發(fā)子組件包時(shí),每一個(gè)包都需要一個(gè)可運(yùn)行的本地開(kāi)發(fā)環(huán)境。

          隨著子組件包的數(shù)量逐漸增多,給每一個(gè)包都單獨(dú)設(shè)立一個(gè)開(kāi)發(fā)環(huán)境,必然會(huì)帶來(lái)更大的維護(hù)成本。我們目前選擇的解決方案是,對(duì)于粒度更細(xì)的子組件包,所有的子包會(huì)公用一套dev的開(kāi)發(fā)倉(cāng)庫(kù),通過(guò) git modules在開(kāi)發(fā)倉(cāng)庫(kù)中嵌套子模塊倉(cāng)庫(kù),實(shí)現(xiàn)了只維護(hù)一套開(kāi)發(fā)環(huán)境,產(chǎn)出多個(gè)子模塊包的組件庫(kù)工廠。


           
          在這種環(huán)境下,還可以做到當(dāng)子模塊之間存在相互依賴時(shí),可以直接引用相對(duì)路徑下其他模塊的源碼,不必為了調(diào)試某個(gè)模塊的代碼,而跑到node_modules里去翻找,徒增調(diào)試難度。
           

          六、組件庫(kù)文檔化與協(xié)同開(kāi)發(fā)


           
          為了讓組件庫(kù)的開(kāi)發(fā)流程更加規(guī)范,減少接入方的溝通成本,對(duì)組件庫(kù)進(jìn)行適當(dāng)?shù)奈臋n梳理是十分必要的,我們使用gitbook 編寫(xiě)組件庫(kù)的文檔,并部署到公司內(nèi)部的books平臺(tái)上。同樣借助于gitlab強(qiáng)大的web hook的能力,實(shí)現(xiàn)了文檔倉(cāng)庫(kù)的自動(dòng)更新與發(fā)布。
           


          與此同時(shí),我們也啟用了協(xié)同開(kāi)發(fā)的模式,讓組件庫(kù)成為一個(gè)內(nèi)部的開(kāi)源庫(kù),用車(chē)產(chǎn)線的研發(fā)同學(xué),可以通過(guò)提交issuse和merge request的方式,自行對(duì)組件庫(kù)中的個(gè)別需求進(jìn)行開(kāi)發(fā),提升開(kāi)發(fā)效率。
           

          七、組件庫(kù)單元測(cè)試、自動(dòng)化與持續(xù)集成



          單元測(cè)試

          當(dāng)組件庫(kù)在開(kāi)發(fā)和交付流程上趨于完善后,在公司G2戰(zhàn)略背景下,為了保證代碼的高質(zhì)量,我們開(kāi)始在組件庫(kù)中接入自動(dòng)化單元測(cè)試。接入單元測(cè)試也是一項(xiàng)十分曲折的過(guò)程。在測(cè)試技術(shù)框架的選型上,綜合考慮了當(dāng)前技術(shù)棧、框架市面通用性等多種因素,最終選擇如下:

          測(cè)試框架:Jest
          選取原因:對(duì)React技術(shù)棧友好,同時(shí)也是React-Native官方推薦的測(cè)試框架
          測(cè)試庫(kù):
          web端 -> @testing-library/react
          RN ->@testing-library/react-native
          選取原因:React的官方測(cè)試庫(kù),對(duì)hooks類型的組件支持度高,選擇這兩個(gè)庫(kù),也是為了能夠保持后續(xù)與react官方版本更新的同步

          自動(dòng)化與持續(xù)集成

          在接入單元測(cè)試后,我們依然借助gitlab的CI/CD,對(duì)整個(gè)組件庫(kù)的流程進(jìn)行自動(dòng)化構(gòu)建與持續(xù)集成交付,在內(nèi)置CtripDevOps或者自定義gitlab-ci.yml的配置下,我們將單元測(cè)試的環(huán)節(jié)加入到了pipeline中,同時(shí)通過(guò)公司統(tǒng)一的sonar檢測(cè),提供最終的組件庫(kù)質(zhì)量統(tǒng)計(jì)報(bào)告。


           

          八、結(jié)語(yǔ)


           
          要搭建一個(gè)相對(duì)完善的組件庫(kù),都是需要經(jīng)過(guò)一系列項(xiàng)目的沉淀的。目前而言,組件庫(kù)的開(kāi)發(fā)流程上依然會(huì)存在一些問(wèn)題,比如版本管理、升級(jí)回退等。時(shí)間是最好的老師,相信在后面的迭代中,我們依然能夠保持初心與熱情,積極探索與發(fā)現(xiàn),構(gòu)建出更加完善的前端工程體系。

          【推薦閱讀】


          “攜程技術(shù)”公眾號(hào)后臺(tái)回復(fù)“新書(shū)”,

          免費(fèi)獲得兩本書(shū)的試讀樣章~

          《攜程架構(gòu)實(shí)踐》

          京東

          當(dāng)當(dāng)

          《攜程人工智能實(shí)踐》

          京東

          當(dāng)當(dāng)



           “攜程技術(shù)”公眾號(hào)

            分享,交流,成長(zhǎng)



          瀏覽 73
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本国内三级片播放 | 91人妻无码成人精品一区91 | 无码H黄 五月乱伦 | 欧美小说视频 | 青娱乐社区精品自拍视频 |