本文由體驗技術團隊Kagol原創。
你的項目是不是正在不斷膨脹,構建速度越來越慢,包體積越來越大,性能越來越慢了?
想拆分到不同的倉庫中分開維護,又擔心代碼不方便複用?
你可能需要將項目改造成 Monorepo 啦!
我將帶大家把一個現有項目改造成 Monorepo 方式,便於擴展和多項目複用。
如果你也有類似的需求,可以點贊、收藏下本文,關鍵時刻也許能幫上忙。
1 為什麼需要做 Monorepo 改造
使用 monorepo 方式組織代碼的前提是:
你有多個項目,並且需要在多個項目中複用組件和邏輯。
如果每個項目都是完全獨立的,沒有什麼共用的代碼(幾乎不太可能),那也許你就不需要用 monorepo 啦。
1.1 Monorepo 的好處
使用 Monorepo 方式組織項目代碼,至少有以下好處:
便於代碼複用:多個倉庫都會用到的組件、工具函數、類型聲明、樣式等,可以放到 common 子包中,需要的倉庫直接 npm install 這個子包就行,就跟 npm install 一個 npm 包一樣容易。獨立構建和部署:每個子包都是一個獨立的項目,有自己的 package.json 文件,獨立安裝依賴、獨立端口和本地啓動、獨立測試、獨立構建和部署,互不影響。降低切換成本:由於只有單一倉庫,clone 代碼、切換分支、安裝依賴比較方便,不用在不同文件夾之間切換。節約磁盤空間:pnpm 天然具備 monorepo 能力,支持全局依賴管理,所有子包之間共享依賴,節約磁盤空間。方便提交PR:由於是單倉庫,增加新組件或給組件增加新特性,只需要提交一個 MR、編寫一次 MR 描述、關聯一次需求/缺陷單。方便代碼檢視:一個完整的特性只需要統一在一個 MR 中檢視,不用在多個倉庫/多個 MR 之間切換。靈活便於擴展:後續增加新的工程只需要在 packages 下增加一個子包,不需要申請新的代碼倉庫,也降低後續倉庫維護成本,比如:配置保護分支 / GitHub Actions / 倉庫標籤等。
1.2 如果不用 Monorepo 會怎麼樣?
- 方式一: 把所有項目放到一個倉庫裏,創建很多文件夾,分別存放不同的項目,通過路由進行項目隔離。
這樣做的好處是所有代碼都在一起,代碼複用方便,直接 ../ 就行;而且不用創建和維護倉庫,不用配置一堆流水線。
壞處也顯而易見,就是項目會不斷膨脹,本地啓動調試會越來越慢、構建打包越來越慢,包體積越來越大,項目越來越卡,最後用户受不了紛紛棄坑。
- 方式二: 將項目拆分到不同的代碼倉庫進行維護。
好處是項目之間相互獨立,不容易耦合,維護起來方便。
壞處就是增加了倉庫維護成本、流水線創建成本,並且不方便項目之間複用代碼。
不管是以上哪種方式,後續項目的演進都是麻煩不斷,要麼代碼量膨脹、性能下降,要麼重複勞動、一堆重複代碼。
Monorepo 可以你幫助減少麻煩,快樂工作!
我們一起來看看具體怎麼改造吧!
2 現有工程改造成 Monorepo 的步驟
假如我們已經有了一個 Vite + Vue3 工程,可以通過 npm run dev 本地啓動,npm run build 進行構建。
基本步驟:
- 增加 packages 目錄用於存放子包,增加 portal 子包
- 把現有工程的 src / public / package.json / vite.config.ts / tsconfig.xx.json / index.html / README.md 等項目啓動和構建相關的目錄和文件全部剪切到 packages/portal 目錄中
- 增加 pnpm-workspace.yaml 文件配置多包路徑
- 根目錄增加 package.json 文件
- 執行 pnpm i 安裝依賴,執行 pnpm -F portal dev 本地啓動
- 將本地啓動命令放到根目錄的 packages.json scripts中,方便啓動
2.1 創建子包
第一步就是在根目錄創建 packages 目錄,增加項目子包,比如項目叫:portal
root
├── packages
| └── portal
| ├── ... // 項目文件和目錄
2.2 現有項目文件放進子包裏
把現有工程的 src / public / package.json / vite.config.ts / tsconfig.xx.json / index.html / README.md 等項目啓動和構建相關的目錄和文件全部剪切到 packages/portal 目錄中
root
├── packages
| └── portal
| ├── index.html
| ├── package-lock.json
| ├── package.json
| ├── public
| ├── README.md
| ├── src
| ├── tsconfig.app.json
| ├── tsconfig.json
| ├── tsconfig.node.json
| └── vite.config.ts
2.3 配置 pnpm-workspace.yaml
根目錄創建 pnpm-workspace.yaml 文件。
packages:
- packages/**
2.4 配置 package.json
項目原來的 package.json 屬於子包,需要放到 portal 子包中。
項目根目錄需要創建一個新的 package.json 文件。
{
"name": "root",
"private": true
}
2.5 改造前後目錄結構對比
2.6 驗證本地啓動和構建命令
執行 pnpm i 安裝依賴
執行 pnpm -F portal dev 本地啓動
執行 pnpm -F portal build 項目構建
如果以上命令都正常,説明本次 Monorepo 改造成功!
2.7 增加便捷命令
將本地啓動命令放到根目錄的 packages.json scripts 中,方便啓動。
{
"name": "root",
"private": true,
+ "scripts": {
+ "dev": "pnpm -F portal dev",
+ "build": "pnpm -F portal build",
+ "preview": "pnpm -F portal preview"
+ }
}
後續啓動項目:pnpm dev
構建項目:pnpm build
3 增加一個新項目 admin
在 packages 目錄下執行 npm create vite admin,選擇 React 框架。
執行 pnpm i 安裝依賴
執行 pnpm -F admin dev 本地啓動 admin 新項目
執行 pnpm -F admin build 構建 admin 新項目
兩個項目同時啓動了。
實現了 portal / admin 兩個項目分開啓動、分開構建、分開管理依賴、分開測試,互不影響,而且 portal 是 Vue 技術棧,admin 是 React 技術棧。
可以在根目錄的 package.json scripts 增加對應的便捷命令。
{
"name": "root",
"private": true,
"scripts": {
"dev": "pnpm -F portal dev",
"build": "pnpm -F portal build",
"preview": "pnpm -F portal preview",
+ "dev:admin": "pnpm -F portal dev",
+ "build:admin": "pnpm -F portal build",
+ "preview:admin": "pnpm -F portal preview"
}
}
改造後的 Monorepo 項目目錄結構,看起來和原來差異不大,就是包了一層 packages,其實整個項目已經脱胎換骨,變成了一個更加讓人“省心”的項目,項目之間的代碼複用更加方便,後續維護和擴展也是非常輕鬆。
root
├── package.json
├── packages
| ├── admin
| | ├── eslint.config.js
| | ├── index.html
| | ├── package.json
| | ├── public
| | ├── README.md
| | ├── src
| | ├── tsconfig.app.json
| | ├── tsconfig.json
| | ├── tsconfig.node.json
| | └── vite.config.ts
| └── portal
| ├── index.html
| ├── package-lock.json
| ├── package.json
| ├── public
| ├── README.md
| ├── src
| ├── tsconfig.app.json
| ├── tsconfig.json
| ├── tsconfig.node.json
| └── vite.config.ts
├── pnpm-lock.yaml
└── pnpm-workspace.yaml
如果有些邏輯 portal / admin 都用到了,我們可以新加一個子包:common
然後在 portal / admin 中引入 common。
pnpm -F portal i common
pnpm -F admin i common
安裝之後直接 import 進行使用即可。
4 總結
本文主要給大家分析了 Monorepo 方式組織項目代碼的好處,以及不使用 Monorepo 可能帶來的麻煩;
然後以一個 Vite + Vue3 項目為例,手把手帶大家一起將它改造成 Monorepo 項目;
在此基礎上,如何擴展一個新項目,並且新項目技術棧用的是 React,卻可以和原來的 Vue 項目共同代碼邏輯。
別猶豫了,動手實踐起來吧!
最近我們新開源了一個基於 Quill 2.0 的富文本編輯器:Fluent Editor。
Fluent Editor:一個基於 Quill 2.0 的富文本編輯器,功能強大、開箱即用!
如果你正在尋找一款功能強大、開箱即用、易於擴展的開源富文本,不妨嘗試下!
- 官網:https://opentiny.github.io/fluent-editor/
- 源碼:https://github.com/opentiny/fluent-editor/ (歡迎 Star ⭐)
- Kagol 個人博客:https://kagol.github.io/blogs
關於 OpenTiny
GitHub:https://github.com/opentiny/tiny-vue (歡迎 Star ⭐)
官網:https://opentiny.design/tiny-vue
B站:https://space.bilibili.com/15284299
小助手微信:opentiny-official
公眾號:OpenTiny