掃二維碼與項(xiàng)目經(jīng)理溝通
我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
為了解決代碼共享、重復(fù)和一致性等問題,越來越多的團(tuán)隊(duì)轉(zhuǎn)向了Monorepo。本文就來了解一下什么是 Monorepo,它們可以帶來哪些好處,以及常用的 Monorepo 開發(fā)工具。幫助我們更好地理解和應(yīng)用這一代碼管理策略。讓我們一起進(jìn)入Monorepo的世界,打破傳統(tǒng)的代碼管理方式,迎接更高效的開發(fā)體驗(yàn)!

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

我們在微信上24小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流