前陣子前端 leader 將公司產品(前台,後台),和 Line Liff,等三個專案用 Angular 的多專案架構合在一起,原本幾乎一模一樣卻有三套要維護的 share UI 和 core ,變成只要維護一個 library 就好,連很多設定檔 ( git, vscode, package, tsconfig…等 ) 都可以共用,這種非常有系統的感覺真的非常專業呀。
多專案架構是 Monorepo 的概念,一個 workspace 就能管理多個專案和庫,目的在提高資源共用性並簡化大型專案的管理。每種語言都有自己建構多專案架構的方法,而 Angular 特別針對它的開發工具鏈設計了一套多專案架構的建立方式。
只需要下一個 CLI 指令( — create-application=false)就能生成這個架構。
它的根資料夾不是專案(app),而是一個 workspace ,裡面有個資料夾 [ projects ],可以放多個專案,比較特別的是 [ projects ] 它還可以放 library 專案,用來放供其他專案使用的共用資源。
檔案結構大概會像這樣:
my-workspace/
├── node_modules/ ← 共用一個 node_modules 庫。
├── projects/ ← 專案都放這裡,名稱固定為 projects。
│ ├── frontend-app/ ← 專案。
│ ├── backend-app/ ← 專案。
│ └── my-lib/ ← library 專案。預設放同一層。
│
│ // 共用的設定檔
├── angular.json
├── package.json
└── tsconfig.base.json
直接建立的話用 CLI 指令就能做到,非常簡單。
但已存在的單一專案要轉成多專案架構就需要手動移動資料夾和修改設定檔,但也很簡單啦。
ng new <專案名稱> 後加上 --create-application=false ,這樣會生成一個空的Workspace(沒有 app)。
ng new my-workspace --create-application=false
此時,你的 workspace 檔案結構是這樣:
my-workspace/
│
├── projects/ (空的)
│
├── angular.json
├── package.json
└── tsconfig.base.json
想加進專案(app)時,可以另外下指令 ng generate application <專案名稱>,比如…
ng generate application frontend
ng generate application admin
想加進庫(library)時,可以下指令 ng generate library <library名稱>,比如…
ng generate library shared-ui
完成後,angular.json 會有個 projects 屬性,裡面會有剛生成的專案和庫。
從 projectType 可以區分是專案還是庫。
{
"version": 1,
"newProjectRoot": "projects",
"projects": {
"frontend": {
"projectType": "application",
"root": "projects/frontend",
"sourceRoot": "projects/frontend/src",
"architect": {
"build": { ... },
"serve": { ... }
}
},
"admin": {
"projectType": "application",
"root": "projects/admin",
"sourceRoot": "projects/admin/src",
"architect": {
"build": { ... },
"serve": { ... }
}
},
"shared-ui": {
"projectType": "library",
"root": "projects/shared-ui",
"sourceRoot": "projects/shared-ui/src",
"architect": { ... }
}
},
"defaultProject": "frontend"
}
手動將單一專案轉成多專案架構也不難,
比如我要將一個 My-App 專案變成多專案架構,
會有這幾個步驟:
除了 angular.json 的 projects 的部分就如剛剛舉例的設定。
其他就是路徑的部分要修改,畢竟根層級路徑變成 porjects/ 了。
比如…
記得在 tsconfig.ts 裡幫 library 的路徑做 alias 設定,
這樣之後引用 library 就可以很簡潔的使用@lib/…:
package.json 可以幫每個專案設定運行專案的 scripts,比如…
"scripts": {
"ng": "ng",
// 專案 frontend 的操作
"start:frontend": "ng serve frontend",
"build:frontend": "ng build frontend",
"test:frontend": "ng test frontend",
// 專案 admin 的操作
"start:admin": "ng serve admin",
"build:admin": "ng build admin",
"test:admin": "ng test admin",
// 所有專案都 build(如果需要)
"build:all": "ng build frontend && ng build admin"
}
建置一個多專案架構雖然簡單,但如何讓 library 能做到彈性地讓每個專案能方便地共用,就需要好好思考。