溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

基于 Lerna 管理 packages 的 Monorepo 項(xiàng)目最佳實(shí)踐

發(fā)布時(shí)間:2020-07-02 19:47:23 來(lái)源:網(wǎng)絡(luò) 閱讀:622 作者:vivo互聯(lián)網(wǎng) 欄目:web開(kāi)發(fā)

本文首發(fā)于 vivo互聯(lián)網(wǎng)技術(shù)
作者:孔垂亮

對(duì)于維護(hù)過(guò)多個(gè)package的同學(xué)來(lái)說(shuō),都會(huì)遇到一個(gè)選擇題,這些package是放在一個(gè)倉(cāng)庫(kù)里維護(hù)還是放在多個(gè)倉(cāng)庫(kù)里單獨(dú)維護(hù),本文通過(guò)一個(gè)示例講述了如何基于Lerna管理多個(gè)package,并和其它工具整合,打造高效、完美的工作流,最終形成一個(gè)最佳實(shí)踐

背景

最近在工作中接觸到一個(gè)項(xiàng)目,這個(gè)項(xiàng)目是維護(hù)一套 CLI,發(fā)到 npm 上供開(kāi)發(fā)者使用。先看一張圖:

基于 Lerna 管理 packages 的 Monorepo 項(xiàng)目最佳實(shí)踐

項(xiàng)目倉(cāng)庫(kù)中的根目錄上就三個(gè)子模塊的文件夾,分別對(duì)應(yīng)三個(gè) package,在熟悉了構(gòu)建和發(fā)布流程后,有點(diǎn)傻了。工作流程如圖中所示:

  1. 使用webpack、babel和uglifyjs把 pkg-a 的 src 編譯到 dist

  2. 使用webpack、babel和uglifyjs把 pkg-b 的 src 編譯到 dist

  3. 使用webpack、babel和uglifyjs把 pkg-main 的 src 編譯到 dist

  4. 最后使用拷貝文件的方式,把pkg-main、pkg-a、pkg-b中編譯后的文件組裝到 pkg-npm 中,最終用于發(fā)布到 npm 上去。

痛點(diǎn)

  1. 不好調(diào)試。因?yàn)樽罱K的包是通過(guò)文件拷貝的方式組裝到一起的,并且都是壓縮過(guò)的,無(wú)法組建一個(gè)自上到下的調(diào)試流程(實(shí)際工作中只能加log,然后重新把包編譯組裝一遍看效果)

  2. 包的依賴關(guān)系不清晰。pkg-a、pkg-b索性沒(méi)有版本管理,更像是源碼級(jí)別的,但邏輯又比較獨(dú)立。pkg-main中的package.json最終會(huì)拷貝到 pkg-npm 中,但又依賴pkg-a、pkg-b中的某些包,所以要把pkg-a、pkg-b中的依賴合并到pkg-main中。pkg-main和pkg-npm的package.json耦合在一起,導(dǎo)致一些本來(lái)是工程的開(kāi)發(fā)依賴也會(huì)發(fā)布到 npm 上去,變成pkg-npm 的依賴包。

  3. 依賴的包冗余。可以看到,pkg-a、pkg-b、pkg-main要分別編譯,都依賴了babel、webpack等,要分別 cd 到各個(gè)目錄安裝依賴。

  4. 發(fā)布需要手動(dòng)修改版本號(hào)。?因?yàn)樽罱K只發(fā)布了一個(gè)包,但實(shí)際邏輯要求這個(gè)包即要全局安裝又要本地安裝,業(yè)務(wù)沒(méi)有拆開(kāi),導(dǎo)致要安裝兩遍。耦合一起,即便使用 npm link 也會(huì)導(dǎo)致調(diào)試?yán)щy,

  5. 發(fā)版沒(méi)有 CHANGELOG.md。?因?yàn)閜kg-a、pkg-b都沒(méi)有真正管理版本,所以也沒(méi)有完善的CHANGELOG來(lái)記錄自上個(gè)版本發(fā)布已來(lái)的變動(dòng)。

整個(gè)項(xiàng)目像是一個(gè)沒(méi)有被管理起來(lái)的 Monorepo。那什么又是 Monorepo 呢?

Monorepo vs Multirepo

Monorepo 的全稱是 monolithic repository,即單體式倉(cāng)庫(kù),與之對(duì)應(yīng)的是 Multirepo(multiple repository),這里的“單”和“多”是指每個(gè)倉(cāng)庫(kù)中所管理的模塊數(shù)量。

Multirepo 是比較傳統(tǒng)的做法,即每一個(gè) package 都單獨(dú)用一個(gè)倉(cāng)庫(kù)來(lái)進(jìn)行管理。例如:Rollup, ...

Monorep 是把所有相關(guān)的 package 都放在一個(gè)倉(cāng)庫(kù)里進(jìn)行管理,每個(gè) package 獨(dú)立發(fā)布。例如:React, Angular, Babel, Jest, Umijs, Vue ...

一圖勝千言:

基于 Lerna 管理 packages 的 Monorepo 項(xiàng)目最佳實(shí)踐

當(dāng)然到底哪一種管理方式更好,仁者見(jiàn)仁,智者見(jiàn)智。前者允許多元化發(fā)展(各項(xiàng)目可以有自己的構(gòu)建工具、依賴管理策略、單元測(cè)試方法),后者希望集中管理,減少項(xiàng)目間的差異帶來(lái)的溝通成本。

雖然拆分子倉(cāng)庫(kù)、拆分子 npm 包是進(jìn)行項(xiàng)目隔離的天然方案,但當(dāng)倉(cāng)庫(kù)內(nèi)容出現(xiàn)關(guān)聯(lián)時(shí),沒(méi)有任何一種調(diào)試方式比源碼放在一起更高效。

結(jié)合我們項(xiàng)目的實(shí)際場(chǎng)景和業(yè)務(wù)需要,天然的 MonoRepo ! 因?yàn)楣こ袒淖罱K目的是讓業(yè)務(wù)開(kāi)發(fā)可以 100% 聚焦在業(yè)務(wù)邏輯上,那么這不僅僅是腳手架、框架需要從自動(dòng)化、設(shè)計(jì)上解決的問(wèn)題,這涉及到倉(cāng)庫(kù)管理的設(shè)計(jì)。

一個(gè)理想的開(kāi)發(fā)環(huán)境可以抽象成這樣:

“只關(guān)心業(yè)務(wù)代碼,可以直接跨業(yè)務(wù)復(fù)用而不關(guān)心復(fù)用方式,調(diào)試時(shí)所有代碼都在源碼中。”

在前端開(kāi)發(fā)環(huán)境中,多 Git Repo,多 npm 則是這個(gè)理想的阻力,它們導(dǎo)致復(fù)用要關(guān)心版本號(hào),調(diào)試需要 npm link。而這些是 MonoRepo 最大的優(yōu)勢(shì)。

上圖中提到的利用相關(guān)工具就是今天的主角 Lerna ! Lerna是業(yè)界知名度最高的 Monorepo 管理工具,功能完整。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI