新聞中心
為了解決代碼共享、重復(fù)和一致性等問題,越來越多的團隊轉(zhuǎn)向了Monorepo。本文就來了解一下什么是 Monorepo,它們可以帶來哪些好處,以及常用的 Monorepo 開發(fā)工具。幫助我們更好地理解和應(yīng)用這一代碼管理策略。讓我們一起進入Monorepo的世界,打破傳統(tǒng)的代碼管理方式,迎接更高效的開發(fā)體驗!

創(chuàng)新互聯(lián)建站服務(wù)項目包括杭錦網(wǎng)站建設(shè)、杭錦網(wǎng)站制作、杭錦網(wǎng)頁制作以及杭錦網(wǎng)絡(luò)營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術(shù)優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關(guān)系等,向廣大中小型企業(yè)、政府機構(gòu)等提供互聯(lián)網(wǎng)行業(yè)的解決方案,杭錦網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務(wù)的客戶以成都為中心已經(jīng)輻射到杭錦省份的部分城市,未來相信會繼續(xù)擴大服務(wù)區(qū)域并繼續(xù)獲得客戶的支持與信任!
什么是 Monorepo ?
Monorepo 是一個包含多個獨立項目,并且具有明確定義的關(guān)系的單個代碼庫。
圖片
一個真正的Monorepo不僅僅是將多個項目的代碼放在同一個代碼庫中。它還需要這些項目之間有明確定義的關(guān)系。如果這些項目之間沒有良好定義的關(guān)系,那么就不能稱之為Monorepo。
類似地,如果一個代碼庫中包含了一個龐大的應(yīng)用,而沒有對其進行分割和封裝,那么這只是一個大型的代碼庫,而不是真正的Monorepo。即使你給它取一個花里胡哨的名字,也不能改變它的本質(zhì)。
事實上,一個優(yōu)秀的Monorepo正好與龐大的代碼庫相反,它應(yīng)該具有良好的結(jié)構(gòu)和模塊化。
圖片
Monorepo 解決了什么問題?
Polyrepo
為了討論的方便,假設(shè)多個代碼庫("polyrepo")是與單一代碼庫("monorepo")相對應(yīng)的概念。polyrepo 表示多代碼庫,是當前開發(fā)應(yīng)用的標準方式:每個團隊、應(yīng)用或項目都有一個代碼庫。通常情況下,每個代碼庫只有一個構(gòu)建產(chǎn)物,并且擁有簡單的構(gòu)建流程。
圖片
行業(yè)之所以采用多代碼庫的方式進行開發(fā),有一個重要原因:團隊自治。團隊希望能夠自主決定使用哪些庫,何時部署應(yīng)用或庫,以及誰可以貢獻或使用他們的代碼。
團隊自治是一種組織架構(gòu)和開發(fā)模式的趨勢,它賦予了團隊更大的自主權(quán)和靈活性。每個團隊擁有自己的代碼庫,可以根據(jù)自己的需求和優(yōu)先級進行獨立的決策和開發(fā)。這種方式能夠提高團隊的效率和創(chuàng)造力,同時也減少了團隊之間的依賴和沖突。
圖片
這些都是好的方面,那么為什么需要采取不同的方式呢?因為這種自治是通過隔離來實現(xiàn)的,而隔離卻會損害協(xié)作。具體來說,在多代碼庫環(huán)境中存在以下常見問題:
- 繁瑣的代碼共享:要在多個代碼庫之間共享代碼,可能需要為共享代碼創(chuàng)建一個專門的代碼庫。這樣就需要設(shè)置工具和持續(xù)集成(CI)環(huán)境,將貢獻者添加到代碼庫中,并設(shè)置包發(fā)布,以便其他代碼庫可以依賴它。更不用說在多個代碼庫之間解決不兼容的第三方庫版本的問題了…
- 大量代碼重復(fù):由于不愿意費事設(shè)置共享的代碼庫,團隊通常會在每個代碼庫中編寫自己的常見服務(wù)和組件的實現(xiàn),這導致了很多代碼重復(fù)。這種做法不僅浪費了時間,而且在組件和服務(wù)發(fā)生變化時增加了維護、安全性和質(zhì)量控制的負擔。
- 對共享庫和消費者進行成本高昂的跨存儲庫更改:在多個代碼庫中進行共享庫的跨庫更改是具有挑戰(zhàn)性且成本較高的。當一個共享庫需要進行關(guān)鍵 bug 修復(fù)或重大變更時,開發(fā)人員需要在各個代碼庫中逐一應(yīng)用這些修改,而這些代碼庫之間可能存在孤立的修訂歷史。這也意味著必須在每個代碼庫中進行相應(yīng)的測試和驗證,確保更改不會引入新的問題。
- 工具不一致:工具鏈的不一致性會給開發(fā)人員帶來額外的負擔。不同的項目使用不同的命令和工具,可能需要花費時間和精力來適應(yīng)和記憶這些差異。而且,當需要在多個項目之間進行切換時,頻繁地切換命令和工具可能會導致混淆和錯誤。
Monorepo
在多代碼庫環(huán)境("polyrepo")中工作時,可能會遇到一些問題。那單一代碼庫("monorepo")是如何解決這些問題的呢?
- 創(chuàng)建新項目無需額外開銷:創(chuàng)建新項目無需額外的開銷。如果所有消費者都在同一個代碼庫中,可以直接在現(xiàn)有的開發(fā)環(huán)境中創(chuàng)建和設(shè)置新項目,避免了額外的資源和配置成本。
- 原子提交跨項目:每次提交都能確保所有項目能夠協(xié)同工作。當在同一次提交中修復(fù)所有問題時,不存在破壞性變更的問題,因為所有修改都是一起完成的。
- 同一版本的所有內(nèi)容:可以避免因項目依賴沖突而導致的不兼容性問題。所有項目都共享同一份代碼庫,使用相同的第三方庫版本,減少了版本管理和沖突解決的復(fù)雜性。
- 開發(fā)靈活性:可以建立一種統(tǒng)一的構(gòu)建和測試應(yīng)用程序的方式,即使這些應(yīng)用程序使用不同的工具和技術(shù)。開發(fā)人員可以自信地為其他團隊的應(yīng)用程序做出貢獻,并驗證其更改是安全的。
Monorepo 工具有哪些?
Monorepo 擁有許多優(yōu)勢,但為了使其發(fā)揮作用,需要使用正確的工具。隨著工作空間的擴大,這些工具必須幫助開發(fā)者保持高效、可理解和可管理。
那 Monorepo 工具應(yīng)該提供些什么呢?
- 本地計算緩存
- 本地任務(wù)編排
- 分布式計算緩存
- 分布式任務(wù)執(zhí)行
- 透明遠程執(zhí)行
- 檢測受影響的項目/包
- 工作區(qū)分析
- 依賴圖可視化
- 代碼共享
- 一致的工具
- 代碼生成
- 項目約束和可見性
注意:除了功能以外,還有其他因素會影響使用體驗。盡管一個工具可能在某些方面功能不如其他工具強大,但由于用戶體驗、成熟度、文檔、編輯器支持等因素的差異,用戶可能會更喜歡使用它。有些功能可以很容易地通過自定義實現(xiàn)來添加,而有些功能則無法通過簡單的修改來實現(xiàn)。因此,除了關(guān)注功能外,還需要綜合考慮其他因素來選擇適合自己需求的工具。
比較流行的 Monorepo 工具如下:
|
工具 |
開發(fā)團隊 |
簡介 |
|
Bazel |
谷歌 |
快速、可擴展、多語言且可擴展的構(gòu)建系統(tǒng)。 |
|
Gradle Build Tool |
Gradle |
專為多項目構(gòu)建而設(shè)計的快速、靈活的多語言構(gòu)建系統(tǒng)。 |
|
Lage |
微軟 |
JS monorepos 中的任務(wù)運行器。 |
|
Lerna |
Nrwl |
一個用于管理具有多個包的 JavaScript 項目的工具。 |
|
Nx |
Nrwl |
下一代構(gòu)建系統(tǒng)具有一流的 monorepo 支持和強大的集成。 |
|
Pants |
Pants Build |
一個快速、可擴展、用戶友好的構(gòu)建系統(tǒng),適用于各種規(guī)模的代碼庫。 |
|
Rush |
微軟 |
適合擁有大量團隊和項目的大型單一倉庫。屬于 Rush Stack 項目系列的一部分。 |
|
Turborepo |
Vercel |
JavaScript 和 TypeScript 代碼庫的高性能構(gòu)建系統(tǒng) |
接下來將逐個功能來比較各個 Monorepo 工具在這些功能上的表現(xiàn)。
本地計算緩存
本地計算緩存是指在進行任務(wù)執(zhí)行時,將任務(wù)的輸入、輸出和中間結(jié)果存儲在本地機器上,以便在后續(xù)的構(gòu)建或測試過程中可以直接使用這些已經(jīng)計算過的結(jié)果,而不需要重新執(zhí)行相同的任務(wù)。
圖片
|
工具 |
是否支持 |
|
Bazel |
|
|
Gradle Build Tool |
Gradle Build Tool 本身提供本地構(gòu)建緩存。Gradle Enterprise 添加了對復(fù)制和管理的支持。 |
|
Lage |
|
|
Lerna |
Lerna v6 具有由 Nx 提供支持的內(nèi)置本地計算緩存。 |
|
Nx |
|
|
Pants |
像React一樣,Nx在從其緩存中恢復(fù)結(jié)果時進行了樹差異比較,這使得它在平均情況下比其他工具更快 |
|
Rush |
利用系統(tǒng) tar 命令更快地恢復(fù)文件。 |
|
Turborepo |
本地任務(wù)編排
本地任務(wù)編排是指在執(zhí)行任務(wù)時,按照規(guī)定的順序和并行方式來管理和執(zhí)行這些任務(wù)。任務(wù)之間可能存在依賴關(guān)系,需要按照正確的順序進行執(zhí)行,同時還可以利用并行計算的優(yōu)勢,提高任務(wù)的執(zhí)行效率。
圖片
|
工具 |
是否支持 |
|
Bazel |
|
|
Gradle Build Tool |
Gradle Build Tool 通過配置提供對并行任務(wù)的支持,并通過其靈活的 Groovy 或 Kotlin DSL 提供任務(wù)編排支持。 |
|
Lage |
|
|
Lerna |
Lerna v6 充分利用了 Nx 來高效地協(xié)調(diào)和并行執(zhí)行任務(wù)。 |
|
Nx |
|
|
Pants |
|
|
Rush |
支持此功能。命令可以被建模為簡單的腳本,也可以作為獨立的“階段”(例如構(gòu)建、測試等)。 |
|
Turborepo |
分布式計算緩存
分布式計算緩存允許在不同的環(huán)境中共享緩存結(jié)果。通過共享緩存,整個組織中的不同部門或團隊可以共享已經(jīng)計算過的結(jié)果,避免重復(fù)構(gòu)建或測試相同的內(nèi)容。
圖片
|
工具 |
是否支持 |
|
Bazel |
|
|
Gradle Build Tool |
Gradle Build Tool 提供遠程分布式緩存。Gradle Enterprise 添加了對復(fù)制和管理的支持。 |
|
Lage |
|
|
Lerna |
Lerna v6 可以連接到 Nx Cloud 以啟用分布式緩存。 |
|
Nx |
|
|
Pants |
|
|
Rush |
Rush 內(nèi)置了對 Azure 和 AWS 存儲的支持,并具有允許自定義緩存提供程序的插件 API。 |
|
Turborepo |
分布式任務(wù)執(zhí)行
分布式任務(wù)執(zhí)行是指將一個命令分布到多臺機器上執(zhí)行的能力,同時在很大程度上保持在單臺機器上運行時的開發(fā)人員體驗。
圖片
|
工具 |
是否支持 |
|
Bazel |
Bazel 的實現(xiàn)是最復(fù)雜的一種,可以擴展到包含數(shù)十億行代碼的存儲庫,設(shè)置起來也很困難。 |
|
Gradle Build Tool |
? Gradle Enterprise可以分布式執(zhí)行測試任務(wù)。 |
|
Lage |
|
|
Lerna |
Lerna v6 可以連接到 Nx Cloud 以實現(xiàn)分布式任務(wù)執(zhí)行。 |
|
Nx |
Nx 的實現(xiàn)并不像 Bazel 那樣復(fù)雜,但可以通過小的配置更改來打開它。 |
|
Pants |
Pant 的實現(xiàn)與 Bazel 類似,并使用相同的遠程執(zhí)行 API。 |
|
Rush |
? Rush 通過選擇性地與 Microsoft 的 BuildXL 加速器集成來提供此功能。 |
|
Turborepo |
透明遠程執(zhí)行
透明的遠程執(zhí)行功能允許開發(fā)人員在本地開發(fā)環(huán)境中執(zhí)行命令,并將這些命令自動透明地分發(fā)到多臺遠程機器上進行執(zhí)行。開發(fā)人員可以像在單臺機器上運行命令一樣,在本地環(huán)境中編寫和執(zhí)行命令,而無需手動切換到遠程機器或修改代碼。
|
工具 |
是否支持 |
|
Bazel |
這是 Bazel 和其他工具最大的區(qū)別 |
|
Gradle Build Tool |
|
|
Lage |
|
|
Lerna |
|
|
Nx |
|
|
Pants |
Pant 的實現(xiàn)與 Bazel 類似,并使用相同的遠程執(zhí)行 API。 |
|
Rush |
|
|
Turborepo |
檢測受影響的項目/包
在進行構(gòu)建或測試操作時,通過檢測變更的內(nèi)容,確定可能受到變更影響的項目或包,從而只針對受影響的項目進行構(gòu)建或測試。
圖片
|
工具 |
是否支持 |
|
Bazel |
? Bazel沒有內(nèi)置支持,但是第三方工具(如target-determinator)使用Bazel的查詢語言提供了這個功能。 |
|
Gradle Build Tool |
Gradle Build Tool 本身提供增量構(gòu)建和最新檢測。 |
|
Lage |
|
|
Lerna |
|
|
Nx |
支持,它的實現(xiàn)不僅查看更改了哪些文件,還查看更改的性質(zhì)。 |
|
Pants |
|
|
Rush |
用于項目選擇的命令行參數(shù)可以檢測哪些項目受到 Git diff 的影響。Rush 還為自動化場景提供了 PackageChangeAnalyzer API。 |
|
Turborepo |
工作區(qū)分析
工作區(qū)是指包含多個項目或代碼庫的根目錄。工作區(qū)分析通過解析工作區(qū)中的項目、文件和依賴關(guān)系,生成一個項目圖,展示了項目之間的相互關(guān)系和依賴。這個項目圖可以幫助開發(fā)人員更好地理解整個工作區(qū)的結(jié)構(gòu)和組織,并能夠快速定位和處理相關(guān)的項目。
圖片
|
工具 |
是否支持 |
|
Bazel |
? Bazel 允許開發(fā)人員編寫 BUILD 文件。一些公司構(gòu)建了分析工作區(qū)源并生成 BUILD 文件的工具。 |
|
Gradle Build Tool |
可以使用build.gradle(Groovy腳本)或build.gradle.kts(Kotlin腳本)來編寫構(gòu)建任務(wù)。 |
|
Lage |
|
|
Lerna |
|
|
Nx |
默認情況下,Nx 分析 package.json、JavaScript 和 TypeScript 文件。它是可插拔的,可以擴展以支持其他平臺(例如 Go、Java、Rust)。 |
|
Pants |
這是Pants的最大差異化點。它使用靜態(tài)分析來自動推斷出支持的所有語言和框架的文件級依賴關(guān)系。 |
|
Rush |
Rush項目和單倉庫項目具有相同的 |
|
Turborepo |
Turborepo 分析 package.json 文件。 |
依賴圖可視化
依賴關(guān)系圖可視化工具可以將項目和/或任務(wù)之間的依賴關(guān)系以圖形化的方式呈現(xiàn)出來。這個可視化過程是交互式的,也就是說可以對圖中的節(jié)點進行搜索、過濾、隱藏、聚焦或突出顯示,以及進行查詢操作。
|
工具 |
是否支持 |
|
Bazel |
Bazel 的實現(xiàn)支持自定義查詢語言來過濾掉不感興趣的節(jié)點。 |
|
Gradle Build Tool |
? Gradle Build Scan 提供豐富的依賴關(guān)系信息,并且第三方工具可用于項目/任務(wù)圖。 |
|
Lage |
? Lage 沒有附帶可視化工具,可以編寫自己的可視化工具。 |
|
Lerna |
? Lerna 沒有附帶可視化工具,可以編寫自己的可視化工具。 |
|
Nx |
Nx 配備了交互式可視化工具,可用于過濾和探索大型工作區(qū)。 |
|
Pants |
? Pants并沒有自帶可視化工具,但它可以生成一個包含代碼庫詳細圖結(jié)構(gòu)的JSON文件,該文件可以被處理成可用于可視化工具的輸入數(shù)據(jù)。 |
|
Rush |
? Rush 沒有附帶可視化工具,可以編寫自己的可視化工具。 |
|
Turborepo |
Turborepo 使用 Graphviz 生成執(zhí)行計劃的靜態(tài)圖像和 HTML 文件。該實現(xiàn)不是交互式的。 |
代碼共享
代碼共享是指通過一些方式來方便地分享代碼庫中獨立的代碼片段。
圖片
|
工具 |
是否支持 |
|
Bazel |
可以將任何文件夾標記為一個項目,并通過Bazel的構(gòu)建規(guī)則來實現(xiàn)該項目的共享。 |
|
Gradle Build Tool |
可以發(fā)布可共享的構(gòu)件并從多個倉庫中引用依賴項。 |
|
Lage |
支持,只有npm包可以共享。 |
|
Lerna |
支持,只有npm包可以共享。 |
|
Nx |
支持,任何文件夾都可以標記為一個項目,并且可以進行共享。Nx插件幫助配置WebPack、Rollup、TypeScript和其他工具,以實現(xiàn)共享而不影響開發(fā)人員的工作環(huán)境。 |
|
Pants |
支持打包、發(fā)布和使用代碼構(gòu)件,使用底層語言和框架的標準慣用法。 |
|
Rush |
支持,不鼓勵從未聲明為npm依賴的文件夾導入代碼。這確保了項目可以在單體倉庫之間輕松移動。對于創(chuàng)建包是過于繁瑣的情況,"packlets"提供了一個輕量級的替代方案。 |
|
Turborepo |
支持,只有npm包可以共享。 |
一致的工具
這樣的工具可以幫助開發(fā)人員在不同的技術(shù)棧之間切換時更加輕松和無縫。不管是使用JavaScript框架,還是使用Go、Rust、Java等其他技術(shù),開發(fā)人員都可以獲得相同的工具支持和開發(fā)體驗。這種一致性的工具能夠簡化開發(fā)流程,減少學習成本,并提高團隊的協(xié)作效率。
例如,該工具可以分析package.json和JS/TS文件,以確定JavaScript項目的依賴關(guān)系以及構(gòu)建和測試方法。但是,對于Rust,它會分析Cargo.toml文件,對于Java,它會分析Gradle文件。因此,該工具需要具備插件化的能力。
圖片
|
工具 |
是否支持 |
|
Bazel |
Bazel的構(gòu)建規(guī)則就像是不同技術(shù)和框架的插件。 |
|
Gradle Build Tool |
通過插件生態(tài)系統(tǒng)可以擴展其功能,例如使用CMake進行本地構(gòu)建或使用Webpack進行打包。 |
|
Lage |
只能運行 npm 腳本。 |
|
Lerna |
只能運行 npm 腳本。 |
|
Nx |
Nx是可插拔的。它默認能夠調(diào)用npm腳本,但也可以擴展以調(diào)用其他工具(例如Gradle)。 |
|
Pants |
Pants具有強大的插件API,可以提供統(tǒng)一的用戶體驗(UX),適用于不同的語言和框架。它內(nèi)置了多個插件,包括Python、Java、Scala、Go、Shell和Docker等,同時還有更多的插件正在開發(fā)中。還可以使用相同的API編寫自定義的構(gòu)建規(guī)則。 |
|
Rush |
Rush只針對TypeScript/JavaScript項目進行構(gòu)建,并推薦一種解耦的方法,即使用本地工具鏈或BuildXL單獨構(gòu)建原生組件。理想情況下,Node.js是單體庫開發(fā)者所需的唯一先決條件。 |
|
Turborepo |
Turborepo只能運行npm腳本,但不必安裝Node.js。 |
代碼生成
原生支持生成代碼。
|
工具 |
是否支持 |
|
Bazel |
? 可以使用外部代碼生成器。 |
|
Gradle Build Tool |
? 可以使用外部代碼生成器。 |
|
Lage |
? 可以使用外部代碼生成器。 |
|
Lerna |
? 可以使用外部代碼生成器。 |
|
Nx |
Nx具有強大的代碼生成能力。它使用虛擬文件系統(tǒng),并提供編輯器集成。Nx插件提供了流行框架的生成器,還可以使用其他生成器。 |
|
Pants |
Pants內(nèi)置了適用于流行的代碼生成框架的插件,包括Protobuf/gRPC、Thrift、Scrooge、Avro和SOAP。它還提供了插件API支持,以便輕松地添加新的代碼生成器。Pants支持從單個codegen源生成多種語言的代碼。它能夠通過對codegen源的靜態(tài)分析來推斷依賴關(guān)系,并在這些源發(fā)生變化時正確地使生成的代碼失效。 |
|
Rush |
? Rush的維護者建議將項目模板作為單體庫中的普通項目進行維護,以確保它們能夠在編譯時沒有錯誤。通過一個社區(qū)插件,可以使用項目腳手架命令來生成項目模板。 |
|
Turborepo |
? 可以使用外部代碼生成器。 |
項目約束和可見性
Rush支持定義規(guī)則來約束倉庫內(nèi)的依賴關(guān)系。例如,開發(fā)人員可以將某些項目標記為私有項目,只有他們團隊內(nèi)的人才能依賴這些項目。開發(fā)人員還可以根據(jù)使用的技術(shù)(例如React或Nest.js)標記項目,并確保后端項目不導入前端項目。
圖片
|
工具 |
是否支持 |
|
Bazel |
Bazel支持可見性規(guī)則,這有助于將私有內(nèi)容與公共內(nèi)容、可共享的內(nèi)容等進行分隔。 |
|
Gradle Build Tool |
? 本身不原生支持這樣的規(guī)則,但其豐富的插件功能允許開發(fā)人員開發(fā)類似的規(guī)則。 |
|
Lage |
? 可以使用一組自定義規(guī)則和額外配置的代碼檢查工具(linter)來確保滿足某些約束條件。 |
|
Lerna |
? 可以使用一組自定義規(guī)則和額外配置的代碼檢查工具(linter)來確保滿足某些約束條件。 |
|
Nx |
開發(fā)人員可以根據(jù)自己的需求對項目進行任意方式的注釋,并建立不變量,而Nx將確保這些注釋的有效性。它允許開發(fā)人員注釋哪些是私有的、哪些是公開的、哪些是實驗性的、哪些是穩(wěn)定的等等。Nx還允許為每個包定義公共API,這樣其他開發(fā)人員就無法深層導入到這些包中。 |
|
Pants |
? 雖然原生支持尚未實現(xiàn),但可以編寫自定義插件來強制執(zhí)行此類規(guī)則。 |
|
Rush |
Rush可以根據(jù)項目類型選擇性地要求在引入新的NPM依賴(內(nèi)部或外部)時進行審批。它還支持針對NPM發(fā)布的版本策略。 |
|
Turborepo |
? 可以使用一組自定義規(guī)則和額外配置的代碼檢查工具(linter)來確保滿足某些約束條件。 |
小結(jié)
綜上,Monorepo 是一種代碼管理策略,它將一個項目的所有代碼存儲在一個單獨的版本控制庫中。Monorepo 解決了多個問題:解決了代碼共享與重復(fù)的困擾,提供更好的可追蹤性和一致性。通過使用Monorepo,開發(fā)團隊可以更好地組織、共享和管理代碼,提高開發(fā)效率和協(xié)作質(zhì)量。選擇合適的Monorepo工具并靈活運用,能夠幫助開發(fā)者更好地應(yīng)對復(fù)雜的軟件開發(fā)需求,推動項目的成功完成。
參考:https://monorepo.tools/
網(wǎng)站題目:聊聊HelloMonorepo
文章URL:http://www.5511xx.com/article/cdchgoe.html


咨詢
建站咨詢
