git前端工程实现ci_大前端项目代码重用,也许lerna是最好的选择
我前段時間參與了一個react為主的大前端項目,覆蓋Web、Android、Ios三個平臺。由于整個業務邏輯側重在手機端,且Web端也是到了項目中期才開始啟動,我在搭底層框架時就沒有考慮用類似react-native-web這樣的框架把三端統一,而是分別以react-native和react為主起了兩個項目來應對。
由于無論哪一端,調用的后端微服務集群都是同一個,導致兩個項目中還是不可避免的出現了一些重復邏輯,我嘗試了封裝成npm包來重用邏輯,但僅限于那些通用且變化較少工具類代碼,對于變化頻繁的業務邏輯代碼,封裝出來的npm包時不時就要更新版本,且抽出到項目之外也不易開發和調試,用起來格外麻煩,得不償失。
最近嘗試了lerna,驚喜的發現它不但能解決當時項目的痛點,還能額外帶來一些多項目管理相關的好處。
引入lerna
lerna的名字來源于希臘神話中的九頭蛇海德拉(Lernaean Hydra),拿它形容多項目工程是再貼切不過了。
lerna的引入比想象中簡單,其實,與其說引入lerna,倒不如說是導入到lerna更合適,因為具體的做法是通過命令行創建了一個新的lerna項目,然后把所有項目導入進去。而且在導入的同時,每個項目的git提交記錄也都合并在了一起。
lerna initlerna import 你本地的項目路徑每個被導入的項目都會被存放在根路徑的packages目錄下,下面是我demo項目的截圖,一共引入了三個子項目,分別是:rntest, web-app, shared。
使用lerna來管理項目依賴
引入lerna后,第一件事就是要處理安裝依賴的問題,我們需要用lerna add 命令來代替我們習慣的npm或yarn,比如說現在給截圖中的rntest項目安裝lodash,就要執行下面的命令,該命令的底層實現也還是調用哦npm install之類的命令。
lerna add lodash --scope=rntest不過,執行后你會發現其他項目中package-lock.json都發生了變化,讓人非常困惑,這背后的原因是跟添加依賴后自動執行的安裝命令lerna bootstrap有關。
lerna的依賴提升
lerna可以通過lerna bootstrap一行命令安裝所有子項目的依賴包,而且在安裝依賴時還有依賴提升功能,所謂“依賴提升”,就是把所有項目npm依賴文件都提升到根目錄下,這樣能避免相同依賴包在不同項目安裝多次。比如多個項目都用了redux,通過依賴提升,只需要下載一次放到根目錄的node_modules目錄下,就可供其他所有項目來使用。不過,需要額外的參數--hoist讓依賴提升生效。
lerna bootstrap --hoist但是自動執行lerna bootstrap命令是不帶依賴提升參數的,這就導致上面每個項目的lock文件都會被修改的原因。
當然,要解決這個問題也容易,可以通過lerna的配置來避免npm對lock文件的修改即可,寫法如下:
yarn是lerna的最佳搭檔
lerna默認使用npm作為安裝依賴包工具,但也可以選擇其他工具。yarn在1.0版本之后提供了workspaces的功能,該功能從更底層的地方提供了依賴提升,做的事情跟lerna如出一轍。把它跟lerna放在一起看,簡直就像是為lerna量身定做一樣。因此,推薦在lerna中搭配yarn一起使用。
把npm替換成yarn只需在lerna的配置文件添加兩行代碼即可,配置完以后立刻順暢百倍。
高效的代碼重用
在我參與的這個大前端項目里,多端之間代碼重復的部分包含redux中的業務邏輯、http請求的處理、代碼規范工具的檢查、git鉤子中的自定義腳本等等。在lerna架構下,前兩者可直接抽取到一個獨立的項目,然后被其他項目引用,比如在我的demo中,可以像其他依賴包一樣直接引入shared項目, lerna會自動識別并把它導向內部項目。
import shared from 'shared'這跟直接封裝成npm包的一大區別就是實時更新,修改立刻可見,就像在同一個項目一樣,不影響開發和調試。
git鉤子和自定義腳本的重用
我嘗試把處理git鉤子的工具husky安裝到了根目錄,觸發的事件和自定義腳本能覆蓋到每個項目,給這部分代碼重用帶來了極大便利。比如,不少項目會添加自定義腳本來約束git commit提交時的消息描述,在lerna架構下,只需寫一次即可。
eslint的重用
那些常常需要在根目錄添加配置文件的第三方依賴,比如eslint、prettier、babel等,在lerna中無法簡單粗暴的提升合并到一處。因此,對于eslint這種前端開發已不可或缺的工具,可以嘗試將所有配置項抽取到獨立項目,然后安裝第三方依賴的方式引入,類似eslint-config-airbnb,eslint-config-prettier,eslint-config-google這樣。
不得不說,即便不用lerna框架我們也可以這么做,只不過在`lerna`框架下修改立刻可見,方便了調試和開發。
lerna框架下的CI/CD
多項目的結構無疑給CI/CD帶來挑戰,好在主流的CI框架能完美解決這個問題。比如在gitlab上,only/changes參數完全滿足了我們的需求,讓我們可以為每一個子項目設置單獨的pipeline,比如現在我們設置一個pipeline,只當rntest項目下的文件被修改時才會觸發:
在lerna框架下,所有項目都合在一個工程里,但CI/CD并不必這樣。通過把腳本中的關鍵參數配置到CI/CD的項目內里,共用同一份.gitlab-ci.yml文件,從而能夠實現每個子項目對應一個獨立的CI/CD項目,最終CI/CD結構如下圖:
lerna框架下的子項目權限
由于所有的項目都歸并到了一個lerna工程下,一旦有了訪問權限意味著你可以修改所有子項目中的代碼,在實際的開發工作中多多少少會帶來一些麻煩。比如說,開發web和開發mobile平臺的是兩個不同的團隊,假如我作為web組的一員,一不小心修改了或刪除了mobile項目的文件該怎么辦?假如不加入任何限制,這種事情遲早會發生,我想這可能是lerna框架與生俱來的的痛點。
不幸的是,在lerna框架下,gitlab或github這類第三方代碼托管平臺,本身的權限管理功能無法解決這問題。但好在有其他工具的幫助可以緩解這種痛,我嘗試用來約束開源貢獻者提交PR規范的工具dangerjs來完成權限分隔,利用的信息就是當前gitlab賬號的用戶名,看起來效果還不錯。
可以看到,此工具會在合并MR時,判斷出我gitlab賬號沒有權限修改rntest子項目內的文件,從而禁止合并此MR,并將這些信息自動添加到MR的評論里。當然,腳本判斷是自己寫的僅用作演示,邏輯比較簡陋,腳本代碼如下:
關于dangerjs的部分我會另寫一篇文章詳細介紹。
結語
大前端項目將會是前端發展的趨勢,如何更好的管理大前端項目是每一位前端開發躲不開的課題。lerna框架通過合而為一的理念提供了一種解決方案,通過揚長避短,我們可以發揮出lerna的最大效用。假如你還沒有用過,也許,下一個項目就可以試試看。
參考資料
- https://github.com/lerna/lerna
- https://gitlab.com/twomeetings/lerna-demo (文章中的demo)
- https://classic.yarnpkg.com/en/docs/workspaces/
總結
以上是生活随笔為你收集整理的git前端工程实现ci_大前端项目代码重用,也许lerna是最好的选择的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Datalogic得利捷推出最新读码产品
- 下一篇: 使用泛型解决之前的问题