Nx App 拆分優勢與策略步驟
1. 背景說明
目前前端專案採用 Nx monorepo,原本僅有單一應用程式 shopping-app,同時承載:
- 一般使用者(前台)功能
- 管理者/營運人員(後台)功能
隨著功能擴充與角色複雜度提升,單一 App 逐漸出現以下問題:
- bundle 體積愈來愈大,首屏載入時間增加
- 測試與除錯範圍變廣,改一小段功能要驗證很多頁面
- 權限、導覽、UI 風格混雜在一起,維護成本高
- 部署策略無法細緻,例如:只想更新後台功能但仍須重建整個 App
為解決上述問題,我們規劃將前端拆分為兩個獨立 App,並保留既有路由邏輯與使用者習慣。
2. 拆成兩個 App 的優勢
2.1 架構與責任分離
拆分後我們會有兩個應用:
shopping-app:前台,面向一般使用者backoffice-app:後台,面向管理者/營運人員
優勢:
- 前後台的路由、版型、權限可以完全分開設計
- 開發時不會被另一個角色的 UI 汙染
- 規格討論可以針對各自 App 進行,不互相牽扯
2.2 打包與建置時間優化
在 Nx 下,拆分多個 App 可以搭配:
- incremental build(增量編譯)
- affected:* 指令(只建置有受影響的專案)
實際效果:
- 只修改後台程式碼時,可僅建置
backoffice-app - 前台沒有變動就不需重新 build,CI 時間與成本下降
- 本地開發時可以只啟動自己關心的 App,啟動速度較快
2.3 bundle 大小與載入效能改善
- 前台不再需要下載後台相關的頁面與元件
- Admin 專用 UI / library 不會出現在前台 bundle 中
- Lazy loading 策略可以更乾淨,依 App 設計懸掛不同的 chunk
2.4 權限與安全性清晰化
- 後台 App 可以在 routing 層、部署層各自設計權限控管
- 反向代理(nginx / gateway)可針對不同 path/domain 做額外保護
- 不讓 admin 專用的頁面隨前台一起被發佈
2.5 部署與版本獨立
未來可實現:
- 前台與後台採用不同的發版節奏
- 僅更新後台功能時,不動到前台 bundle
- 甚至可分別部署到不同 domain 或子路徑
3. 拆分核心策略:Clone & Carve
本次拆分採用「Clone & Carve」策略:
先完整複製,再在複製版本中慢慢「削減」成新形狀,而不是直接改原本的 App。
流程概念:
- 先複製現有 App → 得到兩份一模一樣的應用
- 確保兩個 App 都能正常 serve / build
- 在新 App 中逐步刪除不需要的功能頁面
- 建立路由/部署分流
- 拆完後,再逐步抽出共用的 libs
好處:
- 原本的
shopping-app在拆分初期完全不被動到 - 出現問題可以隨時回退到舊的單一 App
- 每個步驟都可以單獨測試與驗證
4. 視覺化流程與目錄結構
4.1 流程圖(文字版)
[現有 shopping-app]
|
v
[複製為 backoffice-app]
|
v
[確認兩者可獨立 serve & build]
|
v
[在 backoffice-app 內刪除前台頁面]
|
v
[建立兩者 routing / 部署分流]
|
v
[未來再抽出 shared libs]
|
v
[Build / 部署 / 權限 全面分離]
4.2 目錄結構變更
拆分前:
apps/
shopping-app/
pages/
home
note
article
tag
search
backoffice
admin
transcript
拆分後:
apps/
shopping-app/
pages/
home
note
article
tag
search
backoffice-app/
pages/
backoffice
admin
transcript
未來再視需求抽出 libs:
libs/
shared-model
shared-api
shared-domain
shared-ui
shared-utils
5. 實作步驟(操作手冊)
以下步驟以 Nx + Angular 為例,重點在「最小異動」與「可隨時回退」。
5.1 複製現有 App
-
在 repo 根目錄複製:
cp -R apps/shopping-app apps/backoffice-app -
確認複製後目錄存在:
apps/
shopping-app/
backoffice-app/
此時兩個 App 的內容完全相同。
5.1.1 Nginx Proxy 導流測試(在拆分前先做)
server {
listen 80;
server_name yourdomain.com;
# 前台路由
location / {
proxy_pass http://localhost:4200;
}
# 後台路由
location /backoffice/ {
proxy_pass http://localhost:4300;
}
# 避免 Angular 路由錯誤
location /backoffice {
return 301 /backoffice/;
}
}
說明:
- 在拆 App 之前,就先建立 nginx proxy 路由
- nginx 充當反向代理,幫助我們先驗證 path 分流
- 然後再複製 app 並建立
backoffice-app
[加上 nginx proxy → 建立 / 與 /backoffice 路由分流]
|
v
[確認分流可正常把流量導向不同開發 port]
|
v
[複製 shopping-app → backoffice-app]
5.2 調整 backoffice 專案設定
在 backoffice-app 底下,調整下列檔案:
-
project.json- 將 name 由
shopping-app調整為backoffice-app - 確定
sourceRoot指向apps/backoffice-app/src
- 將 name 由
-
tsconfig.app.json- 確認
extends、files、include等路徑指向 backoffice-app
- 確認
-
index.html- 修改
<title>例如:Backoffice Admin
- 修改
調整完成後,在本機執行:
nx serve shopping-app
nx serve backoffice-app
確認兩個 App 都能啟動且畫面正常,即可進入下一步。
5.3 在 backoffice-app 中刪除前台頁面
目標:在不影響 shopping-app 的前提下,慢慢把 backoffice-app 修剪成「只有後台功能」的應用。
做法:
-
在
backoffice-app中,先確定 routing 結構與檔案位置 -
針對明顯前台功能(例如:
home,note,article,tag,search),依序:- 從 routing 設定中移除該 path
- 移除頁面元件檔案
- 移除對應的測試檔、style 等
-
每移除一組路由/頁面,都進行一次:
nx build backoffice-app
nx serve backoffice-app確認:
- build 無錯誤
- 主要後台路徑(例如
/backoffice,/admin,/transcript)仍可正常運作
完成後,目錄大致會變成:
apps/
backoffice-app/
pages/
backoffice
admin
transcript
5.4 建立路由與部署分流
在 gateway / nginx / 前端部署設定中,將路由切開,例如:
/或/app→ 指向shopping-appbuild 出來的 bundle/backoffice或/admin→ 指向backoffice-appbuild 出來的 bundle
如此一來:
- 使用者造訪前台時,不會載入後台的程式碼
- 後台可以獨立演進、獨立測試
5.5 拆分完成後的共用程式抽離(後期)
拆分前期不建議直接抽 libs,以免一次改動太大。
當兩個 App 穩定運作後,可以開始評估:
- 共用的 model / DTO
- 共用的 API service
- 共用的 UI components
- 共用的 util / helper
再逐步抽到 libs/ 底下的 shared 專案中,搭配 Nx 提供的 dependency graph 逐步優化結構。
6. 測試與風險控管
6.1 建議的測試順序
每一個拆分步驟都建議至少做:
- 單一 App build 測試:
nx build shopping-app
nx build backoffice-app - 本地手動驗證關鍵路由:
- 前台:主要使用者流程是否正常
- 後台:登入、查詢、管理功能是否正常
- 重要節點時執行 e2e / smoke test
6.2 風險與對應策略
| 風險類型 | 說明 | 對應策略 |
|---|---|---|
| build 爆炸 | 一次改太多檔案 | 每次只做小步驟,改完就 build 一次 |
| 路由錯亂 | path 指到錯的 App | 將前後台 routing 寫在文件與設定中統一管理 |
| 共用程式被誤刪 | 後台仍需要前台某段邏輯 | 初期只刪除「明顯純 UI」頁面,不動 domain / service |
| 難以回退 | 多步驟混在同一 commit | 每個重要步驟分開 commit,必要時可 git revert |
7. 結語
本次 Nx App 拆分的目標,不是追求一次到位的「完美架構」,而是:
- 在不影響現有使用者的情況下,先把前後台在應用層分離開來
- 降低 build 時間與 bundle 大小,改善開發與使用體驗
- 為未來的 libs 抽離與獨立部署鋪路
核心心法:
Keep it working → Keep it separated → Keep it evolving
先讓系統穩定分家,再持續演進結構,是目前最務實、風險最低的拆分路線。