# Nodejs Best Practices

> Node.js 開發原則與決策。框架選擇、非同步模式、安全性與架構。教你思考而非複製。

- Skill: `tai-ch0802/nodejs-best-practices` (Agent Skill)
- Install (CLI): `npx skillmds@latest add tai-ch0802/nodejs-best-practices`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tai-ch0802/nodejs-best-practices/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Tai-ch0802 (https://skillmd.com/u/tai-ch0802)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/tai-ch0802/nodejs-best-practices

---


# Node.js 最佳實踐

> 2025 年 Node.js 開發的原則與決策。
> **學習思考方式，而非記憶程式碼模式。**

---

## ⚠️ 如何使用此技能

此技能教導**決策原則**，而非固定的程式碼複製。

- 不明確時詢問使用者偏好
- 根據情境選擇框架/模式
- 不要每次都預設相同的解決方案

---

## 1. 框架選擇（2025）

### 決策樹

```
你要建構什麼？
│
├── 邊緣/無伺服器（Cloudflare、Vercel）
│   └── Hono（零依賴、超快冷啟動）
│
├── 高效能 API
│   └── Fastify（比 Express 快 2-3 倍）
│
├── 企業/團隊熟悉度
│   └── NestJS（結構化、DI、裝飾器）
│
├── 遺留/穩定/最大生態系
│   └── Express（成熟、最多中介軟體）
│
└── 帶前端的全端
    └── Next.js API Routes 或 tRPC
```

### 比較原則

| 因素 | Hono | Fastify | Express |
|------|------|---------|---------|
| **最適合** | 邊緣、無伺服器 | 效能 | 遺留、學習 |
| **冷啟動** | 最快 | 快 | 中等 |
| **生態系** | 成長中 | 好 | 最大 |
| **TypeScript** | 原生 | 優秀 | 好 |
| **學習曲線** | 低 | 中 | 低 |

### 選擇時要問的問題：
1. 部署目標是什麼？
2. 冷啟動時間重要嗎？
3. 團隊有現有經驗嗎？
4. 有遺留程式碼要維護嗎？

---

## 2. 執行環境考量（2025）

### 原生 TypeScript

```
Node.js 22+：--experimental-strip-types
├── 直接執行 .ts 檔案
├── 簡單專案不需要建構步驟
└── 適用於：腳本、簡單 API
```

### 模組系統決策

```
ESM（import/export）
├── 現代標準
├── 更好的 tree-shaking
├── 非同步模組載入
└── 用於：新專案

CommonJS（require）
├── 遺留相容性
├── 更多 npm 套件支援
└── 用於：現有程式碼庫、某些邊界情況
```

### 執行環境選擇

| 執行環境 | 最適合 |
|----------|--------|
| **Node.js** | 通用、最大生態系 |
| **Bun** | 效能、內建打包器 |
| **Deno** | 安全優先、內建 TypeScript |

---

## 3. 架構原則

### 分層結構概念

```
請求流程：
│
├── 控制器/路由層
│   ├── 處理 HTTP 細節
│   ├── 在邊界進行輸入驗證
│   └── 呼叫服務層
│
├── 服務層
│   ├── 業務邏輯
│   ├── 框架無關
│   └── 呼叫資料存取層
│
└── 資料存取層
    ├── 僅資料存取
    ├── 資料庫查詢
    └── ORM 互動
```

### 為什麼重要：
- **可測試性**：獨立模擬各層
- **彈性**：不影響業務邏輯就能替換資料庫
- **清晰**：每層都有單一職責

### 何時簡化：
- 小型腳本 → 單一檔案可以
- 原型 → 較少結構可接受
- 永遠問：「這會成長嗎？」

---

## 4. 錯誤處理原則

### 集中式錯誤處理

```
模式：
├── 建立自訂錯誤類別
├── 從任何層拋出
├── 在頂層捕獲（中介軟體）
└── 格式化一致的回應
```

### 錯誤回應哲學

```
客戶端取得：
├── 適當的 HTTP 狀態碼
├── 供程式處理的錯誤碼
├── 使用者友善的訊息
└── 無內部細節（安全性！）

日誌取得：
├── 完整堆疊追蹤
├── 請求情境
├── 使用者 ID（如適用）
└── 時間戳
```

### 狀態碼選擇

| 情況 | 狀態碼 | 時機 |
|------|--------|------|
| 錯誤輸入 | 400 | 客戶端發送了無效資料 |
| 未驗證 | 401 | 缺少或無效的憑證 |
| 無權限 | 403 | 有效驗證，但不被允許 |
| 找不到 | 404 | 資源不存在 |
| 衝突 | 409 | 重複或狀態衝突 |
| 驗證錯誤 | 422 | Schema 有效但業務規則失敗 |
| 伺服器錯誤 | 500 | 我們的問題，記錄所有內容 |

---

## 5. 非同步模式原則

### 何時使用各種模式

| 模式 | 適用時機 |
|------|----------|
| `async/await` | 循序非同步操作 |
| `Promise.all` | 平行獨立操作 |
| `Promise.allSettled` | 平行但部分可失敗 |
| `Promise.race` | 逾時或第一個回應優先 |

### 事件迴圈意識

```
I/O 密集型（async 有幫助）：
├── 資料庫查詢
├── HTTP 請求
├── 檔案系統
└── 網路操作

CPU 密集型（async 沒幫助）：
├── 加密操作
├── 圖片處理
├── 複雜計算
└── → 使用 worker threads 或卸載
```

### 避免阻塞事件迴圈

- 生產環境中絕不使用同步方法（fs.readFileSync 等）
- 卸載 CPU 密集工作
- 大資料使用串流

---

## 6. 驗證原則

### 在邊界驗證

```
在哪裡驗證：
├── API 入口點（請求 body/params）
├── 資料庫操作前
├── 外部資料（API 回應、檔案上傳）
└── 環境變數（啟動時）
```

### 驗證函式庫選擇

| 函式庫 | 最適合 |
|--------|--------|
| **Zod** | TypeScript 優先、型別推斷 |
| **Valibot** | 更小的打包（可 tree-shake）|
| **ArkType** | 效能關鍵 |
| **Yup** | 現有 React Form 使用 |

### 驗證哲學

- 快速失敗：儘早驗證
- 要具體：清晰的錯誤訊息
- 不要信任：即使是「內部」資料

---

## 7. 安全原則

### 安全檢查清單（非程式碼）

- [ ] **輸入驗證**：所有輸入已驗證
- [ ] **參數化查詢**：SQL 不用字串串接
- [ ] **密碼雜湊**：bcrypt 或 argon2
- [ ] **JWT 驗證**：始終驗證簽名和過期
- [ ] **速率限制**：防止濫用
- [ ] **安全標頭**：Helmet.js 或等同物
- [ ] **HTTPS**：生產環境全面使用
- [ ] **CORS**：正確配置
- [ ] **密鑰**：僅使用環境變數
- [ ] **依賴**：定期稽核

### 安全思維

```
不信任任何東西：
├── 查詢參數 → 驗證
├── 請求 body → 驗證
├── 標頭 → 驗證
├── Cookie → 驗證
├── 檔案上傳 → 掃描
└── 外部 API → 驗證回應
```

---

## 8. 測試原則

### 測試策略選擇

| 類型 | 用途 | 工具 |
|------|------|------|
| **單元** | 業務邏輯 | node:test、Vitest |
| **整合** | API 端點 | Supertest |
| **E2E** | 完整流程 | Playwright |

### 測試什麼（優先順序）

1. **關鍵路徑**：驗證、支付、核心業務
2. **邊界情況**：空輸入、邊界值
3. **錯誤處理**：事情失敗時會怎樣？
4. **不值得測試的**：框架程式碼、瑣碎的 getter

### 內建測試執行器（Node.js 22+）

```
node --test src/**/*.test.ts
├── 無外部依賴
├── 好的覆蓋率報告
└── 監看模式可用
```

---

## 10. 要避免的反模式

### ❌ 不要：
- 新的邊緣專案使用 Express（用 Hono）
- 生產程式碼中使用同步方法
- 把業務邏輯放在控制器中
- 跳過輸入驗證
- 寫死密鑰
- 不驗證就信任外部資料
- 用 CPU 工作阻塞事件迴圈

### ✅ 要：
- 根據情境選擇框架
- 不明確時詢問使用者偏好
- 成長中的專案使用分層架構
- 驗證所有輸入
- 密鑰使用環境變數
- 最佳化前先做效能分析

---

## 11. 決策檢查清單

實作前：

- [ ] **詢問使用者堆疊偏好了嗎？**
- [ ] **為此情境選擇了框架？**（不只是預設）
- [ ] **考慮了部署目標？**
- [ ] **規劃了錯誤處理策略？**
- [ ] **識別了驗證點？**
- [ ] **考慮了安全需求？**

---

> **記住**：Node.js 最佳實踐是關於決策，而非記憶模式。每個專案都值得根據其需求進行全新考量。

