90 秒總覽
Claude Code 是一個大型 CLI 應用,理解它的關鍵是先掌握「入口→協調層→執行層」的分工。入口負責快速分流,協調層組裝能力,執行層按回合處理。只要抓住這三層的責任邊界,就能用最短時間建立全局觀,後續深入任何模組都不會迷路。
執行路徑(主骨架)
// 啟動重點:先分流,再載入主流程
if (isVersionFlag(args)) {
console.log(VERSION)
return
}
await import('../main.js')
先把最快回答的需求擋在入口,避免整個系統都載入。
input: CLI args
if args 是快速查詢:
直接回覆並結束
else:
初始化設定
組裝命令與工具
交給回合引擎處理
flowchart TD
A[CLI args 輸入] --> B{fast-path 檢查}
B -->|是| C[立即回應並結束]
B -->|否| D[初始化設定]
D --> E[組裝命令與工具]
E --> F[交給回合引擎處理]
路徑判讀重點
- 入口只做分流,不載入任何功能模組。
- 主流程才做完整初始化:設定、命令、工具一次到位。
- 功能模組在回合中按需使用,不提前佔用資源。
關鍵決策(為什麼這樣設計)
決策 1:入口做 fast-path 分流
原因:避免冷啟動延遲。像 --version 這類查詢不需要載入整個系統,直接在入口回覆即可。
代價:每新增 fast-path 指令都要更新入口判斷邏輯,需維護清楚的分流清單。
決策 2:延遲載入主模組
原因:減少首次回應時間。用 await import() 確保只有真正需要完整功能時才載入。
代價:動態載入讓靜態分析難以追蹤模組依賴,IDE 跳轉可能失效。
決策 3:按責任邊界分層而非按功能分檔
原因:降低認知負擔。初學者可以沿「入口→協調→執行」的路線理解,而不必在功能資料夾間跳躍。
代價:同一層的檔案可能很多,需要清楚的命名慣例來區分。
替代方案與取捨
| 方案 | 優點 | 缺點 | 為何未採用/何時可採用 |
|---|---|---|---|
| 全量載入(啟動時載入所有模組) | 程式碼路徑單純,無動態載入複雜度 | 冷啟動慢,簡單查詢也要等完整初始化 | 模組體積小時可行,目前系統規模過大不適合 |
| 多入口(每個功能獨立入口檔) | 各功能完全獨立,啟動最快 | 共用邏輯重複,維護成本高 | 適合微服務架構,單一 CLI 應用不適合 |
| 按功能分檔(feature-based 資料夾) | 單一功能所有檔案集中,修改方便 | 跨功能協調難以追蹤,初學者難建立全局觀 | 功能數量少時可行,目前規模下責任分層更清晰 |
失敗路徑與防護
Failure 1:fast-path 判斷遺漏新指令
症狀:新增的快速查詢指令仍走完整初始化路徑,回應變慢。
防護:新增 fast-path 指令時同步更新入口分流清單,並加入對應的啟動時間測試。
Failure 2:主模組載入失敗
症狀:動態 import() 拋出錯誤,使用者看到未處理的例外。
防護:在入口層加 try/catch,捕獲載入失敗並輸出可讀的錯誤訊息與排查建議。
Failure 3:初始化順序錯亂
症狀:模組依賴尚未就緒就被呼叫,導致 undefined 錯誤或靜默失敗。
防護:初始化階段使用明確的順序控制(如 await 鏈),避免平行初始化產生競態條件。
實作驗證(你改完要怎麼確認)
- 執行
--version:確認立即返回版本號,不觸發完整初始化。 - 執行完整初始化路徑:確認設定、命令、工具皆正確載入且無遺漏。
- 模擬主模組載入失敗:確認錯誤處理有明確回饋,不出現未捕獲例外。
- 檢查初始化順序:確認各模組按依賴關係依序載入,無競態條件。
這四步對應「fast-path、主路徑、錯誤路徑、順序驗證」,是最低可接受驗證集。