前言
近期在管理 Monorepo 當中的檔案時才發現一個有趣的輸出管理模式:桶文件(Barrel File),因此研究一下這種方法的理念與優缺點以架構更好的專案。
什麼是桶文件(Barrel File)模式?
桶文件在 TypeScript 或 JavaScript 當中是指群組化多個輸出的模組於單一檔案當中,方便有個統一的接口去引入。
舉例來說有三個模組(moduleA.js
、moduleB.js
、moduleC.js
),想要運用桶文件的方式統一管理它們,就可以額外創建一個 index.js
並在裡面引入這三個模組,然後再將 index.js
當作這三個模組的接口。
於是可以直接引入這個桶文件來一次性取得以上三個模組:
這樣的模式好處顯而易見,可以有效的管理模組的輸出,增進模組引入的閱讀性,打造乾淨一致的介面供外部使用,特別是在 Icon 庫或元件庫都很常見到這樣的模式。
潛在問題
- 開發體驗疑慮:桶文件可能會讓開發者沒辦法清楚的直接看見模組的來源,特別是在大型專案有多層次的桶文件時。並不是所有開發環境都支援輕鬆跳轉到引入檔案的來源,多層次的輸出引入可能造成困擾。
- 建構與分析開銷:如果使用的 bundler 不支援或沒有正確設定 Tree Shake(移除沒用到的代碼),所有沒有真正用到的模組仍會被打包進去,增加大量的無用代碼。就算有支援的 bundler 也會需要分析桶文件的結構,才能正確移除沒用到的模組。
- 測試與 Linter 開銷:測試會如果每次訪問透過桶文件訪問模組會需要加載每個模組,增加測試的時間。import 檢測相關的 Linter 也會因為桶文件而增加檢測的複雜度。
總結
有的人認為桶文件是個 Anti-Pattern 沒有任何好處,但也有人認為這麼做可以更好的組織模組、統一接口並增進可讀性。
我的想法是如果你的 Bundler 是強大支援 Tree Shake 並且團隊成員都認可這種模式,那麼桶文件是個可行的選項。舉例:Vercel 有寫一篇文章描述 Next 如何克服桶文件造成的問題:How we optimized package imports in Next.js - Vercel
會想調查這個主題是因為目前所在的團隊大量地使用到這樣的模式,但 Vite 並不會在開發中進行 Tree Shake 導致每一次開發環境都有大量的無用代碼被打包進去,嚴重影響到開發體驗。
延伸閱讀
- Barrel files in JavaScript - flaming.codes
- Why you should avoid Barrel Files in JavaScript Modules? - Bart
- Please Stop Using Barrel Files - TkDodo’s blog