All in one:項目級 monorepo 策略最佳實踐

0. ???? 前言

在最近的項目開發中,出現了一個令我困擾的情況。我正在開發的項目 A,依賴了已經線上發佈的項目 B,可是隨着項目 A 的不斷開發,又須要不時修改項目 B 的代碼(這些修改暫時沒必要發佈線上),如何可以在修改項目 B 代碼後及時將改動後在項目 A 中同步? 在項目 A 發佈上線後,如何以一種優雅的方式解決項目 A,B 版本升級後的版本同步問題? 通過一番調研,我發現解決這些問題的最佳方案即是本篇要介紹的 monorepo 策略。前端

1. ???? 什麼是 monorepo 策略?

monorepo 是一種將多個項目代碼存儲在一個倉庫裏的軟件開發策略("mono" 來源於希臘語 μόνος 意味單個的,而 "repo",顯而易見地,是 repository 的縮寫)。將不一樣的項目的代碼放在同一個代碼倉庫中,這種「把雞蛋放在同一個籃子裏」的作法可能乍看之下有些奇怪,但實際上,這種代碼管理方式有不少好處,不管是世界一流的互聯網企業 Google,Facebook,仍是社區知名的開源項目團隊 Babel (以下圖)都使用了 monorepo 策略管理他們的代碼。node

image-20210124225815627

<p style="text-align: center; color: #999;">babel 使用 monorepo 策略管理代碼</p>git

使用 monorepo 策略究竟會給代碼管理者和程序開發者帶來哪些好處? 咱們又該如何在工做中嘗試實踐 monorepo 策略?這正是本文想要探討的話題。但願經過個人一番介紹,您可以對 monorepo 策略有更完整的認知,文章中介紹的工具和思想能夠切實幫助到您和您所在的團隊。github

2. ???? monorepo 策略的優劣

經過 monorepo 策略組織代碼,您代碼倉庫的目錄結構看起來會是這樣:shell

.
├── lerna.json
├── package.json
└── packages/ # 這裏將存放全部子 repo 目錄
    ├── project_1/
    │   ├── index.js
    │   ├── node_modules/
    │   └── package.json
    ├── project_2/
    │   ├── index.js
    │   ├── node_module/
    │   └── package.json
    ...

乍看起來,所謂的 monorepo 策略就只是將不一樣項目的目錄聚集到一個目錄之下,但實際上操做起來所要考慮的事情則遠比看起來要複雜得多。經過分析使用 monorepo 策略的優劣,咱們能夠更直觀的感覺到這裏面所隱晦涉及的知識點。npm

2.1 monorepo 方案的優點

  1. 代碼重用將變得很是容易:因爲全部的項目代碼都集中於一個代碼倉庫,咱們將很容易抽離出各個項目共用的業務組件或工具,並經過 TypeScript,Lerna 或其餘工具進行代碼內引用;
  2. 依賴管理將變得很是簡單:同理,因爲項目之間的引用路徑內化在同一個倉庫之中,咱們很容易追蹤當某個項目的代碼修改後,會影響到其餘哪些項目。經過使用一些工具,咱們將很容易地作到版本依賴管理和版本號自動升級;
  3. 代碼重構將變得很是便捷:想一想到底是什麼在阻止您進行代碼重構,不少時候,緣由來自於「不肯定性」,您不肯定對某個項目的修改是否對於其餘項目而言是「致命的」,出於對未知的恐懼,您會傾向於不重構代碼,這將致使整個項目代碼的腐爛度會以驚人的速度增加。而在 monorepo 策略的指導下,您可以明確知道您的代碼的影響範圍,而且可以對被影響的項目能夠進行統一的測試,這會鼓勵您不斷優化代碼;
  4. 它倡導了一種開放,透明,共享的組織文化,這有利於開發者成長,代碼質量的提高:在 monorepo 策略下,每一個開發者都被鼓勵去查看,修改他人的代碼(只要有必要),同時,也會激起開發者維護代碼,和編寫單元測試的責任心(畢竟朋友來訪以前,咱們從不介意本身的房子究竟有多亂),這將會造成一種良性的技術氛圍,從而保障整個組織的代碼質量。

2.2 monorepo 方案的劣勢

  1. 項目粒度的權限管理變得很是複雜:不管是 Git 仍是其餘 VCS 系統,在支持 monorepo 策略中項目粒度的權限管理上都沒有使人滿意的方案,這意味着 A 部門的 a 項目如果不想被 B 部門的開發者看到就很難了。(好在咱們能夠將 monorepo 策略實踐在「項目級」這個層次上,這纔是咱們這篇文章的主題,咱們後面會再次明確它);
  2. 新員工的學習成本變高:不一樣於一個項目一個代碼倉庫這種模式下,組織新人只要熟悉特定代碼倉庫下的代碼邏輯,在 monorepo 策略下,新人可能不得不花更多精力來理清各個代碼倉庫之間的相互邏輯,固然這個成本能夠經過新人文檔的方式來解決,但維護文檔的新鮮又須要消耗額外的人力;
  3. 對於公司級別的 monorepo 策略而言,須要專門的 VFS 系統,自動重構工具的支持:設想一下 Google 這樣的企業是如何將十億行的代碼存儲在一個倉庫之中的?開發人員每次拉取代碼須要等待多久?各個項目代碼之間又如何實現權限管理,敏捷發佈?任何簡單的策略乘以足夠的規模量級都會產生一個奇蹟(無論是好是壞),對於中小企業而言,若是沒有像 Google,Facebook 這樣雄厚的人力資源,把全部項目代碼放在同一個倉庫裏這個美好的願望就只能是個空中樓閣。

2.3 小結:如何取捨?

沒錯,軟件開發領域歷來沒有「銀彈」。monorepo 策略也並不完美,而且,我在實踐中發現,要想完美在組織中運用 monorepo 策略,所須要的不只是出色的編程技巧和耐心。團隊日程,組織文化和我的影響力相互碰撞的最終結果才決定了想法最終是否能被實現。編程

可是請別灰心的太早,由於雖然讓組織做出改變,統一施行 monorepo 策略困難重重,但這卻並不意味着咱們須要完全跟 monorepo 策略說再見(不然我這篇文章就該到此爲止了)。咱們還能夠把 monorepo 策略實踐在「項目」這個級別,即從邏輯上肯定項目與項目之間的關聯性,而後把相關聯的項目整合在同一個倉庫下,一般狀況下,咱們不會有太多相互關聯的項目,這意味着咱們可以免費獲得 monorepo 策略的全部好處,而且能夠拒絕支付大型 monorepo 架構的利息。json

本文的剩餘篇幅就是對「項目級別 monorepo 實踐」的一些總結,即便您最終沒有選擇 monorepo 策略組織您的代碼,相信文章中提供的一些工程化工具或思路也同樣會對您產生幫助。bootstrap

3. ????????‍???? monorepo 方案實踐

3.1 鎖定環境:Volta

Volta 是一個 JavaScript 工具管理器,它可讓咱們輕鬆地在項目中鎖定 node,npm 和 yarn 的版本。你只需在安裝完 Volta 後,在項目的根目錄中執行 volta pin 命令,那麼不管您當前使用的 node 或 npm(yarn)版本是什麼,volta 都會自動切換爲您指定的版本。babel

所以,除了使用 Docker 和顯示在文檔中聲明 node 和 npm(yarn)的版本以外,您就有了另外一個鎖定環境的強力工具。

並且相較於 nvm,Volta 還具備一個誘人的特性:當您項目的 CLI 工具與全局 CLI 工具不一致時,Volta 能夠作到在項目根目錄下自動識別,切換到項目指定的版本,這一切都是由 Volta 默默作到的,開發者沒必要關心任何事情。

3.2 複用 packages:workspace

使用 monorepo 策略後,收益最大的兩點是:

  1. 避免重複安裝包,所以減小了磁盤空間的佔用,並下降了構建時間;
  2. 內部代碼能夠彼此相互引用;

這兩項好處所有均可以由一個成熟的包管理工具來完成,對前端開發而言,便是 yarn(1.0 以上)或 npm(7.0 以上)經過名爲 workspaces 的特性實現的(⚠️ 注意,支持 workspaces 特性的 npm 目前依舊不是 TLS 版本)。

爲了實現前面提到的兩點收益,您須要在代碼中作三件事:

  1. 調整目錄結構,將相互關聯的項目放置在同一個目錄,推薦命名爲 packages;
  2. 在項目根目錄裏的 package.json 文件中,設置 workspaces 屬性,屬性值爲以前建立的目錄;
  3. 一樣,在 package.json 文件中,設置 private 屬性爲 true(爲了不咱們誤操做將倉庫發佈);

通過修改,您的項目目錄看起來應該是這樣:

.
├── package.json
└── packages/
    ├── @mono/project_1/ # 推薦使用 `@<項目名>/<子項目名>` 的方式命名
    │   ├── index.js
    │   └── package.json
    └── @mono/project_2/
        ├── index.js
        └── package.json

而當您在項目根目錄中執行 npm install 或 yarn install 後,您會發如今項目根目錄中出現了 node_modules 目錄,而且該目錄不只擁有全部子項目共用的 npm 包,還包含了咱們的子項目。所以,咱們能夠在子項目中經過各類模塊引入機制,像引入通常的 npm 模塊同樣引入其餘子項目的代碼。

請注意咱們對子項目的命名,統一以 @<repo_name>/ 開頭,這是一種社區最佳實踐,不只可讓用戶更容易瞭解整個應用的架構,也方便您在項目中更快捷的找到所需的子項目。

至此,咱們已經完成了 monorepo 策略的核心部分,實在是很容易不是嗎?可是老話說「行百里者半九十」,距離優雅的搭建一個 monorepo 項目,咱們還有一些路要走。

3.3 統一配置:合併同類項 - Eslint,Typescript 與 Babel

您必定贊成,編寫代碼要遵循 DRY 原則(Don't Repeat Yourself 的縮寫)。那麼,理所固然地,咱們應該儘可能避免在多個子項目中放置重複的 eslintrc,tsconfig 等配置文件。幸運的是,Babel,Eslint 和 Typescript 都提供了相應的功能讓咱們減小自我重複。

3.3.1 TypeScript

咱們能夠在 packages 目錄中放置 tsconfig.settting.json 文件,並在文件中定義通用的 ts 配置,而後,在每一個子項目中,咱們能夠經過 extends 屬性,引入通用配置,並設置 compilerOptions.composite 的值爲 true,理想狀況下,子項目中的 tsconfig 文件應該僅包含下述內容:

{
  "extends": "../tsconfig.setting.json", // 繼承 packages 目錄下通用配置
  "compilerOptions": {
    "composite": true, // 用於幫助 TypeScript 快速肯定引用工程的輸出文件位置
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src"]
}

3.3.2 Eslint

對於 Eslint 配置文件,咱們也能夠如法炮製,這樣定義子項目的 .eslintrc 文件內容:

{
  "extends": "../../.eslintrc", // 注意這裏的不一樣
  "parserOptions": {
    "project": "tsconfig.json"
  }
}

注意到了嗎,對於通用的 eslint 配置,咱們並無將其放置在 packages 目錄中,而是放在整個項目的根目錄下,這樣作是由於一些編輯器插件只會在項目根目錄尋找 .eslintrc 文件,所以爲了咱們的項目可以保持良好的「開發環境一致性」,請務必將通用配置文件放置在項目的根目錄中。

3.3.3 Babel

Babel 配置文件合併的方式與 TypeScript 一模一樣,甚至更加簡單,咱們只需在子項目中的 .babelrc 文件中這樣聲明便可:

{
  "extends": "../.babelrc"
}

當一切準備就緒後,咱們的項目目錄應該大體呈以下所示的結構:

.
├── package.json
├── .eslintrc
└── packages/
    │   ├── tsconfig.settings.json
    │   ├── .babelrc
    ├── @mono/project_1/
    │   ├── index.js
    │   ├── .eslintrc
    │   ├── .babelrc
    │   ├── tsconfig.json
    │   └── package.json
    └───@mono/project_2/
        ├── index.js
        ├── .eslintrc
        ├── .babelrc
        ├── tsconfig.json
        └── package.json

3.4 統一命令腳本:scripty

在上一步中,咱們儘量的將全部配置文件進行抽象,從而精簡了代碼,並提升了整個項目的一致性。咱們的整個倉庫也所以有了「更濃郁的 monorepo 風味 ☕️」。但若是仔細審視咱們的整個工程文件,還有一處存在着明顯的瑕疵和一些惱人的壞味道,當您仔細審視您的衆多 package.json 文件時,您就知道我在說什麼了 -- scripts 腳本。

若是您的子項目足夠多,您可能會發現,每一個 package.json 文件中的 scripts 屬性都大同小異,而且一些 scripts 充斥着各類 Linux 語法,例如管道操做符,重定向或目錄生成。重複帶來低效,複雜則令人難以理解,這都是須要咱們解決的問題。

這裏給出的解決方案是,使用 scripty 管理您的腳本命令,簡單來講,scripty 容許您將腳本命令定義在文件中,並在 package.json 文件中直接經過文件名來引用。這使咱們能夠實現以下目的:

  1. 子項目間複用腳本命令;
  2. 像寫代碼同樣編寫腳本命令,不管它有多複雜,而在調用時,像調用函數同樣調用;

經過使用 scripty 管理咱們的 monorepo 應用,目錄結構看起來將會是這樣:

.
├── package.json
├── .eslintrc
├── scirpts/ # 這裏存放全部的腳本
│   │   ├── packages/ # 包級別腳本
│   │   │   ├── build.sh
│   │   │   └── test.sh
│   └───└── workspaces/ # 全局腳本
│           ├── build.sh
│           └── test.sh
└── packages/
    │   ├── tsconfig.settings.json
    │   ├── .babelrc
    ├── @mono/project_1/
    │   ├── index.js
    │   ├── .eslintrc
    │   ├── .babelrc
    │   ├── tsconfig.json
    │   └── package.json
    └── @mono/project_2/
        ├── index.js
        ├── .eslintrc
        ├── .babelrc
        ├── tsconfig.json
        └── package.json

注意,咱們腳本分爲兩類「package 級別」與「workspace 級別」,而且分別放在兩個文件夾內。這樣作的好處在於,咱們既能夠在項目根目錄執行全局腳本,也能夠針對單個項目執行特定的腳本。

經過使用 scripty,子項目的 package.json 文件中的 scripts 屬性將變得很是精簡:

{
  ...
  "scripts": {
    "test": "scripty",
    "lint": "scripty",
    "build": "scripty"
  },
  "scripty": {
    "path": "../../scripts/packages" // 注意這裏咱們指定了 scripty 的路徑
  },
  ...
}

大功告成!???? 至此,咱們盡己所能地刪除了整個項目中的重複代碼,讓整個項目變得乾淨,清爽而且有極強的複用性。

???? 小貼士:

別忘了使用 chmod -R u+x scripts 命令使全部的 shell 腳本具有可執行權限,也千萬別忘了把這條貼士寫在您的 README.md 文件中!

3.5 統一包管理:Lerna

<p style="text-align: center; color: #999;">圖片來源:https://github.com/lerna/lerna</p>

我有時會感慨本身的靈感匱乏,怎麼就想不到 Lerna 這樣既有神話色彩又能自我釋義的好名字。您能夠大膽想象,九頭龍的每隻龍頭都在幫您管理着一個子項目,而您只須要騎在龍身上發號施令的場景,這基本上就是咱們使用 Lerna 時的直觀感覺。

這也是爲何當咱們提起 monorepo 策略,就幾乎不得不提到 Lerna 的緣由了,它的確提供了一種很是便捷的方式供咱們管理 monorepo 項目。當子項目越多時,Lerna 就越能顯示其威力。

當多個子項目放在一個代碼倉庫,而且子項目之間又相互依賴時,咱們面臨的棘手問題有兩個:

  1. 若是咱們須要在多個子目錄執行相同的命令,咱們須要手動進入各個目錄,並執行命令;
  2. 當一個子項目更新後,咱們只能手動追蹤依賴該項目的其餘子項目,並升級其版本。

經過使用 Lerna,這些棘手的問題都將不復存在。

當在項目根目錄使用 npx lerna init 初始化後,咱們的根目錄會新增一個 lerna.json 文件,默認內容爲:

{
  "packages": ["packages/*"],
  "version": "0.0.0"
}

讓咱們稍稍改動這個文件,使其變爲:

{
  "packages": ["packages/*"],
  "npmClient": "yarn",
  "version": "independent",
  "useWorkspaces": true,
}

能夠注意到,咱們顯示聲明瞭咱們的包客戶端(npmClient)爲 yarn,而且讓 Lerna 追蹤咱們 workspaces 設置的目錄,這樣咱們就依舊保留了以前 workspaces 的全部特性(子項目引用和通用包提高)。

除此以外一個有趣的改動在於咱們將 version 屬性指定爲一個關鍵字 independent,這將告訴 lerna 應該將每一個子項目的版本號看做是相互獨立的。當某個子項目代碼更新後,運行 lerna publish 時,Lerna 將監聽到代碼變化的子項目並以交互式 CLI 方式讓開發者決定須要升級的版本號,關聯的子項目版本號不會自動升級,反之,當咱們填入固定的版本號時,則任一子項目的代碼變更,都會致使全部子項目的版本號基於當前指定的版本號升級。

Lerna 提供了不少 CLI 命令以知足咱們的各類需求,但根據 2/8 法則,您應該首先關注如下這些命令:

  • lerna bootstrap:等同於 lerna link + yarn install,用於建立符合連接並安裝依賴包;
  • lerna run:會像執行一個 for 循環同樣,在全部子項目中執行 npm script 腳本,而且,它會很是智能的識別依賴關係,並從根依賴開始執行命令;
  • lerna exec:像 lerna run 同樣,會按照依賴順序執行命令,不一樣的是,它能夠執行任何命令,例如 shell 腳本;
  • lerna publish:發佈代碼有變更的 package,所以首先您須要在使用 Lerna 前使用 git commit 命令提交代碼,好讓 Lerna 有一個 baseline;
  • lerna add:將本地或遠程的包做爲依賴添加至當前的 monorepo 倉庫中,該命令讓 Lerna 能夠識別並追蹤包之間的依賴關係,所以很是重要;
# 向 @mono/project2 和 @mono/project3 中添加 @mono/project1
lerna add @mono/project1 '@mono/project{2,3}'

3.5.1 Lerna 高級命令

除了上面介紹到的經常使用命令外,Lerna 還提供了一些參數知足咱們更靈活的需求,例如:

  • --concurrency <number>:參數可使 Lerna 利用計算機上的多個核心,併發運行,從而提高構建速度;
  • --scope '@mono/{pkg1,pkg2}':--scope 參數能夠指定 Lerna 命令的運行環境,經過使用該參數,Lerna 將再也不是一把梭的在全部倉庫中執行命令,而是能夠精準地在咱們所指定的倉庫中執行命令,而且還支持示例中的模版語法;
  • --stream:該參數可以使咱們查看 Lerna 運行時的命令執行信息;

3.5.2 npm 包本地發佈:Verdaccio

看到這裏,您可能想要親自體驗一把使用 Lerna 管理/發佈 monorepo 項目的感受。但是很快您會發現,將示例代碼發佈到真實世界的 npm 倉庫並不是一個好主意,這多少有些使人沮喪,可是別擔憂,您可使用 Verdaccio 在本地建立一個 npm 倉庫做爲代理,而後盡情體驗 Lerna 的種種強大之處。

安裝運行 Verdaccio 很是簡單,您只需運行:

npm install --global verdaccio

在全局安裝 Verdaccio 應用,而後在 shell 中輸入:

verdaccio

便可經過 localhost:4837 訪問您的本地代理 npm 倉庫,別忘了在您的項目根目錄建立 .npmrc 文件,並在文件中將 npm 倉庫地址改寫爲您的本地代理地址:

registry="http://localhost:4873/"

大功告成 ????!每當您執行 lerna publish 時,子項目所構建成的 package 將會發布在本地 npm 倉庫中,而當您執行 lerna bootstrap 時,Verdaccio 將會放行,讓您成功從遠程 npm 倉庫中拉取相應的代碼。

3.6 格式化 commit 信息

至此,咱們已經掌握了組織一個項目級 monorepo 倉庫的全部前沿技巧,最後,讓咱們看看最後一個能夠優化的地方:代碼提交時,約束 commit 信息。

一個 monorepo 倉庫可能被不一樣的開發者提交不一樣子項目的代碼,若是沒有規範化的 commit 信息,在故障排查或版本回滾時毫無心外會遭遇災難。所以,千萬不要小看 commit 信息格式化的重要性(固然,一樣重要的還有代碼註釋!)。

爲了咱們可以一目瞭然的追蹤每次代碼變動的信息,咱們使用 commitlint 工具做爲格式化 commit 信息的不二之選。

顧名思義,commitlint 能夠幫助咱們檢查提交的 commit 信息,它強制約束咱們的 commit 信息必須在開頭附加指定類型,用於標示本次提交的大體意圖,支持的類型關鍵字有:

  • feat:表示添加一個新特性;
  • chore:表示作了一些與特性和修復無關的「家務事」;
  • fix:表示修復了一個 Bug;
  • refactor:表示本次提交是由於重構了代碼;
  • style:表示代碼美化或格式化;
  • ...

我強烈建議您遵循該規範編寫您的 commit 信息,不要偷懶,堅持下去,您的 git 日誌將會顯得整齊,有條理,富有表現力,同時,您也會收到同行的交口稱讚,人人都會以和您這樣優雅的工程師合做爲榮。

除了限定 commit 信息類型外,commitlint 還支持(雖然不是必須的)顯示指定咱們本次提交所對應的子項目名稱。假如咱們有一個名爲 @mono/project1 的子項目,咱們針對該項目提交的 commit 信息能夠寫爲:

git commit -m "feat(project1): add a attractive button" # 注意,咱們省略了 @mono 的項目前綴

毫無疑問,這將會使咱們的 commit 信息更具表現力。

咱們能夠經過下面的命令安裝 commitlint 以及周邊依賴:

npm i -D @commitlint/cli @commitlint/config-conventional @commitlint/config-lerna-scopes commitlint husky lerna-changelog

注意到了嗎?我偷偷安裝了 husky,它可以幫助咱們在提交 commit 信息時自動運行 commitlint 進行檢查,但在這以前,咱們須要再在根目錄下的 package.json 文件里加點料,像這樣:

{
 ...
 "husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  }
 ...
}

爲了可以讓 commitlint 感知咱們的子項目名稱,咱們還需在項目根目錄中增長 commitlint.config.js 文件,並設置文件內容爲:

module.exports = {
  extends: [
    "@commitlint/config-conventional",
    "@commitlint/config-lerna-scopes",
  ],
};

至此,咱們統一併規範化了 monorepo 項目的 commit 信息,終於整個 monorepo 工程化的最後一塊拼圖被咱們拼上了!

(順便一提,您能夠經過在命令行執行 echo "build(project1): change something" | npx commitlint 命令便可驗證您的 commit 信息是否經過 commitlint 的檢查。)

4. ???? 如何從 multirepo 遷移至使用 monorepo 策略?

至此,咱們學會了如何採用 monorepo 策略組織項目代碼的最佳實踐,或許您已經開始躍躍欲試想要嘗試前文提到的種種技巧。從 0 搭建一個 monorepo 項目,固然沒問題!但是若是要基於已有的項目,將其轉化爲一個使用 monorepo 策略的項目呢?

還記得嗎?成百里者半九十,您還有一些坑要踩。不過好在您在這裏還可以獲得個人幫助,沒必要客氣!

或許您注意到了,Lerna 爲咱們提供了 lerna import  命令,用來將咱們已有的包導入到 monorepo 倉庫,而且還會保留該倉庫的全部 commit 信息。然而實際上,該命令僅支持導入本地項目,而且不支持導入項目的分支和標籤 ????。

那麼若是咱們想要導入遠程倉庫,或是要獲取某個分支或標籤該怎麼作呢?答案是使用 tomono,其內容是一個 shell 腳本。

使用 tomono 導入遠程倉庫,您所須要作的只有兩件事:

  1. 建立一個包含全部須要導入 repo 地址的文本文件;
  2. 執行 shell 命令:cat repos.txt | ~/tomono/tomono.sh(這裏咱們假定您的文本文件名爲 repos.txt,且您將 tomono 下載在用戶根目錄;

repo 文件內容示例以下:

// 1. Git倉庫地址  2. 子項目名稱  3. 遷移後的路徑
git@github.com/backend.git @mono/backend packages/backend
git@github.com/frontend.git @mono/frontend packages/frontend
git@github.com/mobile.git @mono/mobile packages/mobile

至此,咱們也掌握了將現有項目遷移至 monorepo 項目的方法。到這時候,您已絕非再是 monorepo 界的門外漢!

恭喜您 !!????

5. ???? 小結

在本篇文章中,咱們共同瞭解了「什麼是 monorepo 策略」以及「monorepo 策略的優劣」,而且一塊兒學習實踐了 monorepo 策略的一些最佳實踐。您必定也意識到,即便您的工做場景暫時沒法實踐 monorepo 策略,閱讀本篇文章所學習到的種種方法,工具和思想也能夠運用到您當下的工做之中。

固然,本文所介紹的這些方法和思想總有過期的一天,而且社區也從未中止對更好地實踐 monorepo 策略的探索,說不定您過一陣子就會有更好的想法 ,填補某個領域的空白。但願到時候您也能總結出一篇文章,爲 JavaScript 社區貢獻一份力量。到時候請千萬別忘了回到個人評論區留言,讓我分享您的成就。

關於 monorepo 這個主題,我就暫且帶您探索到這裏,後會有期:)

6. ???? 參考文獻

  1. ???? JavaScript and TypeScript Monorepos
  2. ???? Why you should use a single repository for all your company’s projects
  3. ???? Advantages of monorepos
  4. ???? lerna管理前端packages的最佳實踐
  5. ???? 基於lerna和yarn workspace的monorepo工做流
  6. ???? Monorepos in the Wild
  7. ???? Monorepos: Please don’t!
  8. ???? Monorepo: please do!
  9. ???? Introduction to Lerna
  10. ???? monorepo 遷移實踐

7. ???? 擴展閱讀

  1. 介紹實踐 monorepo 生態:awesome-monorepo
  2. 一篇介紹 Google 如何將數十億代碼經過 monorepo 方式組織的論文:Why Google Stores Billions of Lines of Code in a Single Repository
  3. 一篇針對 Google 的調研報告,詳盡地分析了 monorepo 的優劣: Advantages and Disadvantages of a Monolithic Repository

8. ???? 招聘信息

阿里巴巴淘系用戶增加團隊正在如飢似渴的尋找志同道合的夥伴,若是您準備好迎接適度的挑戰,在讓更多人喜歡手淘的同時,也讓本身快速成長,歡迎您發送簡歷至個人郵箱:kongtang.lb@alibaba-inc.com,我十分期待收到您的訊息。

相關文章
相關標籤/搜索