Node.js 檔案系統進階:內建 Glob 匹配與文件監控實戰

在過去的開發經驗中,當我們需要「找出一目錄下所有的 .js 檔案」或是「監聽整個資料夾的變動」時,通常會直覺地安裝 globchokidar 套件。然而,隨著 Node.js 版本的演進,這些功能現在都已經內建在 node:fs 模組中了。

這篇文章將帶你掌握如何利用原生 API 實現高效的文件處理。

內建 Glob 匹配 (v22+)

Node.js 22.0.0 開始,node:fs 模組提供了原生的 glob 同步與非同步方法。這讓搜尋特定模式的檔案路徑變得極其簡單。

1. 基本用法

假設我們想搜尋 src 目錄下所有的快照檔案(例如 .spec.js):

const { glob, globSync } = require('node:fs/promises');

async function findFiles() {
  // 找出所有 sub-directory 中的 .js 檔案
  const files = await glob('src/**/*.js');

  for await (const entry of files) {
    console.log('找到檔案:', entry);
  }
}

findFiles();

2. 排除特定路徑 (Exclude)

你可以透過 exclude 參數排除不感興趣的目錄(如 node_modules):

const files = await glob('**/*.ts', {
  exclude: (path) => path.includes('node_modules') || path.includes('dist'),
});

原生檔案監控:Recursive Watch

監控檔案變動是開發熱重載 (Hot Reload) 或自動化工具的核心。雖然 fs.watch 存在已久,但早期在不同作業系統上的支援度不一。現在,Node.js 提供了更穩定的遞迴監控支援。

遞迴監聽整個目錄

不需要再手動巡覽資料夾,只需要設定 { recursive: true }

const fs = require('node:fs');

// 監控整個 project/src 資料夾
const watcher = fs.watch('./src', { recursive: true }, (eventType, filename) => {
  if (filename) {
    console.log(`事件類型: ${eventType}`);
    console.log(`變動檔案: ${filename}`);
  }
});

watcher.on('error', (err) => {
  console.error('監控發生錯誤:', err);
});

console.log('正在監控檔案變動中...');

實務技巧:高效遍歷子目錄 (Recursive Readdir)

如果你不需要模式匹配 (Glob),只是單純想列出所有檔案,使用 readdir 並配合 recursive 選項會比遞迴函數更高效。

const { readdir } = require('node:fs/promises');

async function listAllFiles() {
  const files = await readdir('./content', { recursive: true });
  console.log('所有檔案清單:', files);
}

為什麼要用原生 API 取代套件?

  1. 減少依賴地獄:減少 node_modules 的體積,降低供應鏈安全風險。
  2. 降低維護成本:不需要追蹤第三方套件的重大更新 (Breaking Changes) 或棄用訊息。
  3. 優化啟動效能:減少了解析大量第三方程式碼的時間,對於 CLI 工具尤為明顯。
版本提醒:原生 Glob 功能目前在 Node.js 22 中仍處於實作穩定期。如果你需要在 Node.js 18 或 20 環境下使用,建議先檢查版本相容性,或繼續使用成熟的第三方套件。

總結

  1. glob 讓你像在終端機一樣靈活地搜尋檔案。
  2. fs.watch({ recursive: true }) 是建立本地開發工具的最佳拍檔。
  3. 掌握原生 fs 的現代特性,能讓你的 Node.js 程式更純粹且更具前瞻性。