建立前端依賴治理規範文件,.dependency-cruiser.cjs 已參照此 ADR。 內容包含: - Layer Model 四層架構定義 - Feature Isolation 規則說明 - CI 整合配置 (pnpm dep-check) - Severity 分級策略 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
5.7 KiB
5.7 KiB
ADR-014: Dependency Governance
狀態: 已採用 日期: 2026-03-26 決策者: CTO
背景
AWOOOI 前端專案 (apps/web) 隨著功能擴展,元件間的依賴關係日趨複雜:
- Feature 間相互引用: agent/approval/incident/dashboard 元件互相 import,導致修改一處牽動多處
- 分層架構混亂: ui 層引用 feature 層、hooks 引用 components,違反單向依賴原則
- 循環依賴: A → B → C → A 造成難以追蹤的 bundle 問題
- 缺乏自動化檢查: 僅靠 Code Review 把關,容易遺漏
這些問題導致:
- 重構風險高,修改一個元件可能影響多個頁面
- 測試困難,無法隔離測試單一 feature
- 新人學習曲線陡峭
決策
採用 dependency-cruiser 工具,在 CI 階段自動檢查依賴規則。
理由
為什麼選 dependency-cruiser
- 成熟穩定: npm 週下載量 100K+,持續維護
- 規則靈活: 支援 regex、path match、severity 分級
- CI 友善: 非零退出碼可阻擋違規 PR
- 視覺化: 可產出依賴圖 (dot/svg)
- TypeScript 原生支援: 無需額外配置
考慮過的替代方案
| 方案 | 優點 | 缺點 |
|---|---|---|
| ESLint import/no-restricted-paths | 現有工具鏈 | 規則表達力有限 |
| NX enforce-module-boundaries | 強大 | 需導入 NX 生態系 |
| 手動 Code Review | 零成本 | 不可靠、不可擴展 |
技術實作
1. Layer Model (四層架構)
Layer 0: Pages (app/)
├── 可引用: 所有層
├── 職責: 路由、佈局、頁面組裝
│
Layer 1: Features (components/agent, approval, incident, dashboard)
├── 可引用: Layer 2, Layer 3
├── 禁止: 互相引用 (agent ↔ approval ↔ incident ↔ dashboard)
├── 職責: 業務邏輯封裝
│
Layer 2: Shared (components/shared, layout)
├── 可引用: Layer 3
├── 禁止: 引用 Layer 1 (下行依賴)
├── 職責: 跨 Feature 共用元件
│
Layer 3: Primitives (components/ui, lib/, stores/, hooks/)
├── 可引用: 僅外部套件
├── 禁止: 引用 components (保持純淨)
├── 職責: 基礎工具、原子元件
2. 依賴方向 (單向流動)
Pages (L0) → Features (L1) → Shared (L2) → Primitives (L3)
↓ 禁止 ↓ 禁止
互相引用 反向引用
3. Feature Isolation 規則
每個 Feature 為獨立模組,禁止橫向依賴:
❌ agent/xxx.tsx → import from 'approval/yyy'
❌ approval/xxx.tsx → import from 'incident/yyy'
❌ incident/xxx.tsx → import from 'dashboard/yyy'
✅ agent/xxx.tsx → import from 'shared/yyy'
✅ approval/xxx.tsx → import from 'ui/zzz'
4. 配置檔案 (.dependency-cruiser.cjs)
module.exports = {
forbidden: [
// Feature Isolation (L1 禁止互相引用)
{
name: "feature-isolation-agent",
severity: "error",
from: { path: "apps/web/src/components/agent" },
to: { path: "apps/web/src/components/(approval|incident|dashboard)" }
},
// ... 其他 feature 同理
// Shared 禁止下行引用 (L2 → L1)
{
name: "shared-no-feature-import",
severity: "error",
from: { path: "apps/web/src/components/shared" },
to: { path: "apps/web/src/components/(agent|approval|incident|dashboard)" }
},
// Primitives 禁止引用 components (L3 保持純淨)
{
name: "hooks-no-component-import",
severity: "warn",
from: { path: "apps/web/src/hooks" },
to: { path: "apps/web/src/components" }
},
// 禁止循環依賴
{
name: "no-circular",
severity: "error",
from: {},
to: { circular: true }
},
// Components 禁止反向引用 app 層
{
name: "components-no-app-import",
severity: "error",
from: { path: "apps/web/src/components" },
to: { path: "apps/web/src/app" }
}
]
}
5. CI 整合
package.json:
{
"scripts": {
"dep-check": "depcruise apps/web/src --config .dependency-cruiser.cjs"
}
}
ci.yaml:
- name: Dependency Check
run: pnpm dep-check
6. Severity 分級
| Level | 行為 | 使用場景 |
|---|---|---|
error |
CI 失敗 | Feature Isolation、循環依賴 |
warn |
輸出警告 | L3 引用 components (過渡期) |
info |
僅紀錄 | 監控用 |
執行方式
Phase 1: 啟用 (本週)
.dependency-cruiser.cjs配置完成pnpm dep-checkscript 加入- CI workflow 加入 dep-check step
- ADR-014 文件建立
Phase 2: 修復違規 (下週)
- 修復現有 Feature Isolation 違規
- 修復 Shared → Feature 違規
- 警告轉為錯誤 (hooks/stores/lib)
Phase 3: 持續維護
- 新 PR 自動檢查
- 季度產出依賴圖供架構審查
後果
優點
- 架構可維護: 依賴方向明確,修改影響範圍可預測
- 自動化檢查: CI 阻擋違規,不再依賴人工 Review
- Feature 可獨立開發: 各 Feature 團隊可平行作業
- 測試隔離: 可針對單一 Feature 進行單元測試
缺點
- 初期修復成本: 需花時間修復現有違規
- 學習成本: 開發者需理解 Layer Model
風險
- 過度嚴格: 某些合理的跨 Feature 需求可能被誤擋
- 緩解: 使用
severity: warn過渡期,必要時新增白名單
- 緩解: 使用