2021年管理Monorepo代碼庫的11種出色工具
如今,許多工具可以在20個不同的文件夾中運行“npm install”和“npm run build”。但是,并不是所有的工具都能促進正確的monorepo。
促進一個正確的單體開發(fā)意味著要解決一些挑戰(zhàn),比如為分離的模塊運行測試和構(gòu)建過程,能夠從項目中獨立發(fā)布模塊,以及管理變更對項目中每個受影響的依賴模塊的部分影響。
挑戰(zhàn)的清單還在繼續(xù),甚至包括“瑣碎”的事情,比如你如何管理issues和PRs,這可能會隨著你的開發(fā)規(guī)模而變得困難。
請注意,一個monorepo不是一個整體的應(yīng)用程序(!) ——它不是一次性構(gòu)建或部署的,它是一組單獨開發(fā)的應(yīng)用程序。
什么是 monorepo?
國慶期間10月5日尤大公開了vue3.0已完成的源碼,也是采用了monorepo管理模式,看來monorepo確實有其獨到的優(yōu)勢。
monorepo是一種將多個package放在一個repo中的代碼管理模式,摒棄了傳統(tǒng)的多個package多個repo的模式。
目前 Babel, React, Angular, Ember, Meteor, Jest等許多開源項目都使用該種模式來管理代碼。
解決的問題
- 多個repo難以管理,編輯器需要打開多個項目;
- 某個模塊升級,依賴改模塊的其他模塊需要手動升級,容易疏漏;
- 公用的npm包重復(fù)安裝,占據(jù)大量硬盤容量,比如打包工具webpack會在每個項目中安裝一次;
- 對新人友好,一句命令即可完成所有模塊的依賴安裝,且整個項目模塊不用到各個倉庫去找;
帶來的問題
- 所有package代碼集中在一個項目,單個項目體積較大;
- 所有package代碼對所有人可見,無法做權(quán)限管理;
在這篇綜述中,我收集了一些世界上最好的工具來構(gòu)建一個“monorepo”,你可以在一個項目里面構(gòu)建多個模塊,并且有不錯的開發(fā)者體驗,可以擴展。
這個列表并沒有進行排名,旨在根據(jù)每個工具的優(yōu)點來概述其優(yōu)勢。希望能幫助你節(jié)省時間,找到合適的工具。
歡迎在下方評論,分享自己的心得。
1. Yarn Workspaces
Yarn Workspaces 的目標是簡化與monorepos的工作,以更明確的方式解決 yarn link 的一個主要用例。你的依賴關(guān)系可以鏈接在一起,這意味著你的工作空間可以相互依賴,同時總是使用最新的代碼。這也是比 yarn link更好的機制,因為它只影響你的工作空間樹而不是你的整個系統(tǒng)。
Workspaces有助于解決一些問題,使其成為一個很好的單兵裝備。
- 它設(shè)置了一個單一的 node_modules,不需要在項目中的不同包中重復(fù)或克隆依賴關(guān)系。
- 你的所有項目依賴都將被安裝在一起,從而給Yarn更大的空間來更好地優(yōu)化它們。
- Yarn將使用一個單一的鎖文件,而不是為每個項目使用不同的鎖文件,這意味著更少的沖突和更容易的審查。
- 它允許你改變你的一個軟件包的代碼,并讓使用它的其他軟件包立即看到這些變化。對一個包的源代碼的任何修改都會立即應(yīng)用到其他包中。
因此,Yarn Workspaces是一個非常強大的組合,可以和列表中的幾乎所有工具,特別是Bit、Nx和Lerna等工具一起使用,作為你的monorepo管理抽象的下層。
不過,你也可以直接用workspaces發(fā)布。當一個工作空間被打包到一個存檔中時,它會動態(tài)地將任何 workspace: 依賴關(guān)系替換為一個包的版本,因此您可以將結(jié)果包發(fā)布到遠程注冊表,而無需運行中間步驟——消費者將能夠像使用任何其他包一樣使用發(fā)布的工作空間。太酷了!
2. Bit
Bit是用于構(gòu)建模塊化項目的下一代工具。這是一種新的、令人興奮的單倉庫方法,在這種方法中,由同一個項目(同一個Bit工作空間)管理的模塊實際上分布在不同的范圍內(nèi),而不考慮倉庫。
Bit讓你以完全解耦的方式拆分模塊的開發(fā),享受簡單的、整體的開發(fā)體驗來協(xié)調(diào)一切。
使用bit,你可以在你的項目中解耦組件,這樣每個組件都是獨立開發(fā)、構(gòu)建、測試和發(fā)布的。每個組件都是使用特殊的環(huán)境進行開發(fā)和構(gòu)建的,這些環(huán)境是可擴展和可重用的,這樣你就可以快速定制和再次使用它們。
Bit的工作空間管理著項目中所有組件之間的關(guān)系。當你對任何組件進行更改時,Bit會單獨構(gòu)建和測試它,并將更改傳播到依賴關(guān)系圖中。
組件可以作為獨立的包,批量發(fā)布到NPM和/或bit.dev平臺,用于協(xié)作、消費和文檔。
Bit的UI可以幫助你查看你的monorepo的開發(fā)情況。當你編寫代碼時,每個組件都會被記錄、測試、構(gòu)建等,你可以通過實時反饋和熱重載直觀地看到正在發(fā)生的事情。
Bit提供了解耦的開發(fā)環(huán)境--可重用和可定制的模塊,這些模塊將獨立組件整個生命周期所需的不同服務(wù)配置和“捆綁”在一起,如編譯、捆綁、測試、磨合、文檔等。
Bit的工作空間以簡單而全面的方式解耦組件開發(fā)
掌握組件圖——Bit定義、管理并幫助你利用項目中所有組件之間的關(guān)系。
圖形驅(qū)動的構(gòu)建——當您對某個組件進行更改時,Bit會自動檢測依賴于它的其他組件,并“知道”只構(gòu)建依賴組件的受影響的圖形。
“圖形驅(qū)動的構(gòu)建”也意味著,萬一一個組件被標記了新的發(fā)布版本(在被導(dǎo)出到Bit的云端之前),Bit不僅會在每個受影響的組件上運行構(gòu)建,而且會確保給它們標記一個新的發(fā)布版本。
隔離的測試和構(gòu)建——每個組件都是在項目外部隔離地構(gòu)建和測試的,因此您可以確切地看到更改的影響。
組件構(gòu)建管道——您可以在可重用的管道中構(gòu)建作業(yè),該管道可應(yīng)用于項目或所有項目中的所有組件。
批量發(fā)布——在Bit monorepo中開發(fā)的每個組件都可以作為一個獨立的包發(fā)布。Bit去掉了配置每個組件的“package.json”和其他設(shè)置文件的所有開銷。你要做的就是運行'bit tag',這樣Bit就會自動給所有修改過的組件打上版本補丁(支持semver規(guī)則),然后批量發(fā)布修改。
可重復(fù)使用的文檔模板——每個組件都使用可重復(fù)使用和可定制的模板進行文檔化,Bit為您自動完成大部分工作。用MDX工作?也許還可以添加一些可視化的例子?沒問題。
獨立渲染的組合——每個組件都是完全獨立渲染的,完全在項目之外渲染,渲染的視覺效果(在編寫代碼時熱重新加載)成為每個組件文檔的一部分。
3. NX
NX是一套先進的可擴展的開發(fā)工具,適用于monorepos,非常強調(diào)現(xiàn)代全棧Web技術(shù)。
空NX monorepo
NX的目標是通過CLI(帶編輯器插件)提供整體的開發(fā)體驗,并提供可控代碼共享和一致代碼生成的功能。它還提供了增量構(gòu)建,因此它不會在你的每一次提交中重建和重新測試所有內(nèi)容,從而加快構(gòu)建時間。
有了Nx,你可以使用你喜歡的框架,集成你可能已經(jīng)在使用的現(xiàn)代工具。例如,NX可以讓你使用與Cypress、Jest、Typescript、Prettier和其他工具的開箱即用的集成。
NX團隊還提供了NX云,通過云中的智能計算記憶和更快的構(gòu)建來幫助使用NX的團隊更快地交付。
4. Rush
Rush是由微軟+開源的一個強大的monorepo基礎(chǔ)設(shè)施,它的目的是幫助你在一個倉庫中構(gòu)建和發(fā)布許多包。
登陸頁面和一些組件,兩個項目,一個倉庫
rush的一些主要功能包括一個單一的NPM安裝(也可以和Yarn和pnpm一起使用),所以你可以將所有項目的所有依賴關(guān)系安裝到一個共同的文件夾中,使用隔離的符號鏈接為每個項目重新構(gòu)建一個準確的“node_modules”文件夾。
這也有助于確保沒有幻影依賴,所以你不會意外地導(dǎo)入一個在package.json中缺失的庫,也不會在node_modules中發(fā)現(xiàn)10份lib的依賴重復(fù)。
Rush交互式CLI不錯
自動本地鏈接意味著你所有的項目都會自動地相互建立符號鏈接,當你做了一個改變,你可以看到下游的效果,而不需要發(fā)布任何東西,也沒有任何 npm link 的麻煩。
Rush獨特的安裝策略為你的所有項目生成一個快速安裝的單一收縮/鎖定文件。Rush會檢測你的依賴關(guān)系圖,并以正確的順序構(gòu)建你的項目,所以如果兩個包之間沒有直接的依賴關(guān)系,Rush會將它們作為單獨的進程并行構(gòu)建。
如果你只打算使用你的repo中的幾個項目,Rush提供了子集和增量構(gòu)建,所以 rush rebuild --to
當你想發(fā)布的時候,Rush支持批量發(fā)布,所以它會檢測哪些包有變化,自動跳轉(zhuǎn)所有相關(guān)的版本號,并在每個文件夾中運行 npm publish 。
Rush還有助于實施和執(zhí)行發(fā)展政策。例如,當創(chuàng)建PR時,你可以要求開發(fā)人員提供受影響項目的主要/次要/補丁日志條目,這些條目隨后將在發(fā)布時匯總到一個變更日志文件中。它還可以幫助你執(zhí)行諸如發(fā)布前的審查、特定的依賴版本等東西。
5. Lerna
Lerna(以多頭野獸Hydra的家命名)是一個“用于管理帶有多個包的JavaScript項目的工具”。
Lerna的創(chuàng)建是為了解決Babel的多包問題,以優(yōu)化使用git和npm管理多包倉庫的工作流程,它本質(zhì)上是一種工具和腳本,可以有效地管理和發(fā)布許多獨立版本的包在一個Git倉庫中。
- my-lerna-repo/
- package.json
- packages/
- package-1/
- package.json
- package-2/
- package.json
Lerna 的兩個主要命令是 lerna bootstrap 和 lerna publish。bootstrap 會將 repo 中的依賴關(guān)系連接在一起,publish 會幫助發(fā)布任何更新的包。
您可以使用以下兩種模式之一來管理項目:固定(Fixed)或獨立(Independent)。
固定模式的Lerna項目是以單一的版本行來操作的,版本是保存在你的項目根目錄下的 lerna.json 文件中的 version 鍵。當您運行 lerna publish 時,如果一個模塊在上次發(fā)布后被更新,它將被更新到您發(fā)布的新版本。這是Babel目前使用的模式。
一個帶有Yarn Workspaces的Lerna例子
獨立模式Lerna項目允許維護者相互獨立地增加包的版本,每次發(fā)布時,你都會收到一個提示,提示你每一個已經(jīng)改變的軟件包,以指定它是一個補丁,小的,大的或自定義的變化。獨立模式可以讓你更具體地更新每個包的版本,對于一組包來說是有意義的。
“lerna.json”文件是一個匹配包含 package.json 的目錄的globs列表,這也是lerna識別“葉子”包的方式(相對于管理整個repo的開發(fā)依賴和腳本)。例子:
- {
- "version": "1.1.3",
- "npmClient": "npm",
- "command": {
- "publish": {
- "ignoreChanges": ["ignored-file", "*.md"],
- "message": "chore(release): publish",
- "registry": "https://npm.pkg.github.com"
- },
- "bootstrap": {
- "ignore": "component-*",
- "npmClientArgs": ["--no-package-lock"]
- }
- },
- "packages": ["packages/*"]
- }
即使你不打算發(fā)布到NPM,Lerna仍然可以在monorepo中幫助管理版本管理和常見的開發(fā)任務(wù)。
6. Bazel構(gòu)建系統(tǒng) (Google)
谷歌推出了Bazel build system,它是一個類似于Make、Maven和Gradle的開源構(gòu)建和測試工具,使用的是人類可讀的高級構(gòu)建語言。Bazel支持多種語言的項目,并為多種平臺構(gòu)建輸出。它支持大型單一倉庫中的大型代碼庫或跨多個倉庫的大型代碼庫和大量用戶。
Uber開發(fā)者使用Bazel來構(gòu)建他們的Go monorepo。Uber用Go編寫了大部分的后端服務(wù)和庫,在2018年,這些服務(wù)和庫都被歸納到一個大型的Go monorepo中,現(xiàn)在有超過10萬個文件。Bazel讓這個項目得以擴展,縮短了構(gòu)建時間,并支持其發(fā)展。
這是一個不錯的小型開源項目,以Bazel作為演示:thundergolfer/example-bazel-monorepo
Bazel被設(shè)計成大規(guī)模工作,并支持跨分布式基礎(chǔ)設(shè)施的增量密封構(gòu)建,這是大型代碼庫所必需的。有了Bazel的遠程緩存,構(gòu)建服務(wù)器還可以共享它們的構(gòu)建工件。Bazel緩存所有以前完成的工作,并跟蹤對文件內(nèi)容和構(gòu)建命令的更改。只有在包或包的依賴關(guān)系發(fā)生更改時,才構(gòu)建和測試包。
Bazel可以在Linux、macOS和Windows上運行。Bazel可以從同一個項目為多個平臺構(gòu)建二進制文件和可部署的包,包括桌面、服務(wù)器和移動設(shè)備。支持許多語言,你可以擴展Bazel來支持任何其他語言或框架。
7. Buck構(gòu)建系統(tǒng) (Facebook)
Buck是一個鼓勵創(chuàng)建由代碼和資源組成的小型可重用模塊的構(gòu)建系統(tǒng),支持不同平臺上的各種語言。
它是由Facebook開發(fā)和使用的,作為FB單體的官方構(gòu)建系統(tǒng),由于被Uber開發(fā)者等團隊使用,大大縮短了構(gòu)建時間,因此名聲大噪。而AirbnbEng的團隊則將構(gòu)建速度提高了50%,將應(yīng)用程序縮小了30%。
Uber憑借buck獲得了更好的構(gòu)建結(jié)果
Buck被設(shè)計用來構(gòu)建一個monorepo,而對monorepo設(shè)計的支持激發(fā)了Buck對cell和項目的支持。
Facebook的經(jīng)驗是,將所有的依賴關(guān)系維護在同一個版本庫中,可以更容易地確保所有開發(fā)者擁有正確的代碼版本,并簡化了進行原子提交的過程。
Buck常用于Android和iOS開發(fā)。
8. Pants構(gòu)建系統(tǒng)(Twitter)
2014年,Twitter推出了名為Pants的monorepo構(gòu)建系統(tǒng)。今天,在v2版本上,Pants的目標是成為一個快速、可擴展的構(gòu)建系統(tǒng),以適應(yīng)不斷增長的代碼庫。目前,它的重點是Python,很快就會支持其他語言。
Pants使用細粒度的工作流,并將每個工作單元與副作用隔離,因此可以利用所有可用的內(nèi)核。Pant的一些最佳特性包括明確的依賴建模、細粒度的無效化、共享結(jié)果緩存、并發(fā)執(zhí)行、遠程執(zhí)行,以及通過插件API的可擴展性和可定制性。
Pants引擎是用Rust寫的,為的是性能。構(gòu)建規(guī)則是用類型化的Python 3寫的,為了熟悉和簡單。該引擎的設(shè)計使得細粒度的無效化、并發(fā)性、密封性、緩存和遠程執(zhí)行自然發(fā)生,而無需規(guī)則作者的干預(yù)。
9. Please構(gòu)建系統(tǒng)
Please是一個跨語言的構(gòu)建系統(tǒng),強調(diào)高性能、可移植性、可擴展性和正確性。
請確保構(gòu)建步驟是在自己的密封環(huán)境中執(zhí)行的,只能訪問被賦予權(quán)限的文件和env變量。增量構(gòu)建意味著它只構(gòu)建它需要的東西,它還提供了任務(wù)并行性,以及分布式緩存,以實現(xiàn)大規(guī)模的可靠和高性能的構(gòu)建系統(tǒng)。
Please的目標也是專注于開發(fā)體驗,所以你可以享受一個常用的CLI,并為使用自動完成的常見任務(wù)定義別名。
Please用Go編寫,Please提供所有這些用戶體驗,沒有運行時依賴。并且,沒有需要處理太多配置的單個大工作區(qū)文件。
10. Oao
Oao并不是列表中最成熟、最豐富、最容易使用的工具,但它還是很有趣。它是一個基于Yarn的,有意見的monorepo管理工具,p提供monorepo功能,如安裝所有的依賴關(guān)系,添加/刪除/升級子包的依賴關(guān)系,驗證版本號,確定更新的子包,一次性發(fā)布所有的東西,更新變更日志等。
Oao可以讓你在所有子包上運行命令或 package.json 腳本,串行或并行,可選擇遵循反向依賴樹。而且,它支持yarn workspaces,從整體上優(yōu)化了monorepo依賴樹,簡化了bootstrap以及依賴的添加/升級/刪除。
支持非單包發(fā)布:從oao’s的發(fā)布前檢查、標簽、版本選擇、變更日志更新等方面受益,也可以在你的單包、非單包中使用。需要注意的是,Oao使用的是同步版本方案,所以在根級的 package.json 中配置了一個主版本,而子包也將與該版本同步。你可以在這里嘗試一下。
11. Bolt
Boltpkg旨在成為一個“超級功能JavaScript項目管理工具”。
Bolt在Yarn的基礎(chǔ)上實現(xiàn)了workspaces的概念。Bolt CLI在很大程度上是Yarn CLI的替代品,你可以在任何Yarn項目中使用它。
我們知道,workspaces是嵌套在一個更大的項目/repo中的,每個workspaces都可以有自己的依賴關(guān)系,有自己的代碼和腳本。workspaces也可以歸入子目錄進行組織。
使用Bolt,你可以一次安裝所有這些包的依賴關(guān)系(而且你可以做得非常非???。而且,當你從一個工作區(qū)指定一個依賴關(guān)系到另一個工作區(qū)時,它將被鏈接到源代碼。這樣,當你去測試你的代碼時,你所有的變化都會被一起測試。
來源:https://blog.bitsrc.io/11-tools-to-build-a-monorepo-in-2021-7ce904821cc2
作者:Jonathan Saring
本文轉(zhuǎn)載自微信公眾號「前端全棧開發(fā)者」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系前端全棧開發(fā)者公眾號。