幾天前,曉東船長微信問我,你們團隊有沒有monorepo的實踐,我很遺憾的告訴他沒有,但這在我心裡播下了一顆探索的種子,剛好最近老總要搞內蒙古的新專案,我和另一個前端兄弟組成雙槍敢死隊進行保駕護航,於是我就開始探索,有沒有一種可能,可以一個倉庫管理多個專案,這裡說的管理是指有條理有規範的管理,而不是說硬是把幾個專案蹂躪到一起。
在版本控制系統中,monorepo是一種軟體開發策略,其中許多專案的程式碼儲存在同一儲存庫中。這種軟體工程實踐至少可以追溯到2000年代初期,當時被稱為「共用程式碼庫」。一個相關的概念是整體,但是儘管整體將其子專案合併為一個大型專案,但整體倉庫可能包含獨立的專案。(翻譯自維基百科)
簡單地說,Yarn Workspaces是Yarn提供的monorepo的依賴管理機制,從Yarn 1.0開始預設支援,用於在程式碼倉庫的根目錄下管理多個package的依賴
具體的教學,我覺得官網已經寫的很詳細了,我沒有必要復讀一遍,所以我這邊只介紹我這個專案相關的一些關鍵點的介紹。
我是這樣子做架構的, 將專案一分為二,applications表示應用程式目錄,裡面包含了一些專案,比如企業端、資金端、平臺端,以及小程式和h5等,而packages這一塊的話,是我把applications中公共的部分抽離出來,做到多可複用。
除此之外,專案還做了一些優化,比如
設定了eslint + prettier 去規範團隊的程式碼
設定了husky和commitlint去規範團隊的程式碼提交
專案的目錄結構是這樣子的
applications/ent: 企業端
applications/plat: 平臺端
applications/fund: 資金端
applications/mina: 小程式/h5
packages/utils: 通用工具包
packages/componets: 通用元件包
packages/service: 通用服務包
packages/openapi: 通用 openapi 介面包
packages/constants: 通用常數包
packages/types: 通用型別包
packages/styles: 通用樣式包
packages/hooks: 通用勾點包
根目錄下的package.json
如下:
{
"name": "",
"version": "1.0.0",
"description": "",
"main": "index.js",
"repository": "",
"author": "",
"license": "MIT",
"private": true,
"workspaces": [
"applications/*",
"packages/*"
],
"scripts": {
"build": "yarn workspaces run build",
"clean": "yarn workspaces run clean",
"lint:fix": "yarn workspaces run lint:fix",
"prettier:fix": "yarn workspaces run prettier:fix",
"ent": "yarn workspace @sunyard-fin/ent",
"fund": "yarn workspace @sunyard-fin/fund",
"plat": "yarn workspace @sunyard-fin/plat",
"mina": "yarn workspace @sunyard-fin/mina",
"components": "yarn workspace @sunyard-fin/components",
"constants": "yarn workspace @sunyard-fin/constants",
"openapi": "yarn workspace @sunyard-fin/openapi",
"service": "yarn workspace @sunyard-fin/service",
"types": "yarn workspace @sunyard-fin/types",
"styles": "yarn workspace @sunyard-fin/styles",
"utils": "yarn workspace @sunyard-fin/utils"
},
"devDependencies": {
"@commitlint/cli": "^17.0.3",
"@commitlint/config-conventional": "^17.0.3",
"eslint": "^8.15.0",
"husky": "^8.0.1",
"lint-staged": "^13.0.3",
"prettier": "^2.7.1",
"typescript": "^4.7.4",
"@antfu/eslint-config": "^0.23.0",
"eslint-plugin-prettier": "4.0.0",
"eslint-config-prettier": "8.5.0"
},
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
"lint-staged": {
"*.{md,json}": [
"prettier --write"
],
"*.{css,js,jsx,vue,ts,tsx}": [
"prettier --write",
"eslint --fix --cache"
]
}
}
這裡需要注意的好幾點是
"workspaces": [
"applications/*",
"packages/*"
],
"build": "yarn workspaces run build",
這句話的意思就是構建打包所有的專案包
"ent": "yarn workspace @sunyard-fin/ent",
設定了樓上這句話以後,就相當於一個快捷方式,你不用進入子專案去執行,直接在根目錄執行yarn ent dev
就可以進入開發環境了,就相當於進入子目錄執行yarn dev
, 然後可能你也看到了,這裡的專案名不一定要跟目錄名字一樣的,使用@xxx
是不是感覺更有儀式感一點呢。
比如說我要給企業端新增utils包的話,可以執行yarn workspace @sunyard-fin/ent add @sunyard-fin/utils -D
, 當然你也可以直接寫到對應專案的package.json裡面
給所有專案都安裝一個包,執行yarn add -D -W typescript
,這就會給所有專案安裝typescript包
其他的就按照正常使用yarn來。
monorepo適合運用在大型專案中,結合yarn1.x使用的好處是不用每個專案都安裝一遍依賴,這極大的減少專案的體積,然後管理程式碼也更有條理了,各個模組清晰了很多,也做到了高可複用。
其實最開始的選型上,也考慮過用pnpm、yarn2、lerna等等,時間緊任務重,我沒有太多的精力去一個一個調研,粗略看了下yarn1.x針對於我們目前這個專案夠用了,而且引入也沒有啥弊端目前看來,然後也是天然整合的,就不用再額外地增加學習成本,yarn2的話也很好,只不過是我設定yarn set version berry
好像我不科學自強就成功不了,考慮到這是一個團隊(額,雖然也就我和另一個兄弟哈哈哈),所以我還是比較拘謹沒有采用2.x,嗯。
MonoRepo: https://en.wikipedia.org/wiki/Monorepo
yarn2 workspaces: https://yarnpkg.com/features/workspaces
yarn1 workspaces: https://classic.yarnpkg.com/en/docs/workspaces