Circular Dependency
2022-12-15
在 JavaScript 開發中,Circular Dependency(循環依賴)是一個常見但也容易被忽視的問題。簡單來說,當模組 A 引用了模組 B,而模組 B 又反過來引用了模組 A,就形成了循環依賴。這種情況不只發生在兩個檔案之間,也可能是一連串的引用鏈:A -> B -> C -> A。
為什麼這是一個問題?
JavaScript 的模組系統(無論是 CommonJS 還是 ES Modules)在處理循環依賴時,通常不會直接報錯導致程式崩潰,但會導致未預期的行為。
最常見的情況是,當模組 A 正在執行並試圖引用模組 B 時,如果模組 B 因為循環依賴的關係還沒有完全初始化,那麼 A 拿到的模組 B 內容可能是不完整的,甚至是一個空物件。這會導致 undefined 錯誤,而且這類錯誤通常很難除錯,因為它們取決於模組的載入順序。
如何解決?
解決循環依賴的根本方法是重構程式碼。通常有以下幾種策略:
- 與其依賴,不如傳入:將依賴轉為參數傳入,而不是直接 import。
- 提取共用邏輯:將 A 和 B 共同需要的部份提取到第三個模組 C。讓 A 和 B 都依賴 C,而不是彼此依賴。
使用工具檢測
單靠人眼檢查很難發現複雜的循環依賴。我們可以利用工具來協助。這裡推薦一個輕量且快速的靜態分析工具:dpdm。
dpdm 能夠解析 TypeScript 和 JavaScript 檔案,並找出其中的循環依賴。它的優點是不需要複雜的設定檔,直接透過 CLI 指令就能使用。
安裝方式:
pnpm install -D dpdm
使用方式非常簡單,直接指定你的入口檔案即可:
pnpm dlx dpdm ./src/index.ts
# 或者
pnpm dlx dpdm ./src/main.js
執行後,如果專案中有循環依賴,dpdm 會直接列出具體的檔案路徑和引用鏈,讓你一目了然。如果沒有問題,它會顯示 “No circular dependencies found”。
相比於整合在 Webpack 中的 plugin,dpdm 作為一個獨立的 CLI 工具,可以在 CI/CD 流程中更靈活地使用,確保程式碼在庫存入前就解決掉循環依賴的問題。