【GitHub Actions CI 實戰】#02 前端自動化:React + ESLint 程式碼品質檢查

測驗:前端自動化 React + ESLint 程式碼品質檢查

共 5 題,點選答案後會立即顯示結果

1. 在 CI 環境中安裝 npm 依賴時,應該使用哪個指令?

  • A. npm install
  • B. npm ci
  • C. npm update
  • D. npm init

2. 在 GitHub Actions 的 setup-node 中加入 cache: 'npm' 的主要目的是什麼?

  • A. 確保每次都安裝最新版本的套件
  • B. 自動更新 package-lock.json
  • C. 快取依賴套件,加速後續 CI 執行
  • D. 啟用 npm 的安全性檢查

3. 在 ESLint 設定檔中,規則嚴重程度 'error' 代表什麼?

  • A. 只是警告,不影響 CI 結果
  • B. 違反規則會導致 CI 失敗
  • C. 自動關閉這條規則
  • D. 會自動修正問題

4. react-hooks/rules-of-hooks 這個 ESLint 規則主要檢查什麼?

  • A. React Hook 必須在正確位置使用(如不能在條件式中)
  • B. useEffect 的依賴陣列是否完整
  • C. 變數是否有被使用
  • D. 程式碼的排版格式

5. 在 CI 中執行程式碼品質檢查時,通常「不會」使用下列哪個指令?

  • A. npm run lint
  • B. npm run format:check
  • C. npm run lint:fix
  • D. npm run type-check

一句話說明

讓 GitHub 在每次 push 時自動檢查 React 程式碼品質。

前置知識

  • 已讀過第 1 篇:GitHub Actions 核心概念(workflow、job、step)
  • 基本 React 開發經驗
  • 了解 npm 套件管理

這篇教你看懂什麼

讀完這篇,你會看懂:

  1. React 專案裡的 ESLint 設定檔在幹嘛
  2. 前端 CI workflow 每一行在做什麼
  3. npm cinpm install 差在哪
  4. 快取 node_modules 怎麼加速 CI

最小範例:前端 CI Workflow

這是一個完整但最小的前端 CI workflow:

# .github/workflows/frontend-lint.yml
name: Frontend Lint

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - run: npm run lint
Code language: PHP (php)

這段 workflow 做了什麼:

  1. 每次 push 或 PR 到 main 時觸發
  2. 準備 Ubuntu 環境,安裝 Node.js 20
  3. 安裝專案依賴(用 npm ci)
  4. 執行 ESLint 檢查

逐行翻譯:Workflow 檔案

name: Frontend Lint              # 這個 workflow 的名稱,會顯示在 GitHub Actions 頁面

on:
  push:
    branches: [main]             # 推到 main 分支時執行
  pull_request:
    branches: [main]             # 對 main 發 PR 時執行

jobs:
  lint:                          # 定義一個叫 lint 的工作
    runs-on: ubuntu-latest       # 在最新版 Ubuntu 上跑

    steps:
      - uses: actions/checkout@v4           # 把程式碼拉下來

      - uses: actions/setup-node@v4         # 安裝 Node.js
        with:
          node-version: '20'                # 用 Node 20 版
          cache: 'npm'                      # 自動快取 npm 依賴

      - run: npm ci                         # 安裝依賴套件

      - run: npm run lint                   # 執行 lint 指令
Code language: PHP (php)

核心概念翻譯

npm ci vs npm install

指令 意思 什麼時候用
npm install 安裝依賴,可能更新 lock 檔 本機開發
npm ci 嚴格照 lock 檔安裝,更快 CI 環境

Vibe Coder 記這個就好: CI 裡看到 npm ci,就是「快速且嚴格地安裝依賴」。

# CI 裡用這個
- run: npm ci

# 不要用這個(會慢,而且可能裝到不同版本)
- run: npm install
Code language: PHP (php)

cache: ‘npm’ 是什麼

- uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'           # 快取 npm 依賴,下次跑更快
Code language: PHP (php)

翻譯: 第一次跑要下載所有套件(可能 2-3 分鐘),加了快取後,下次只要幾秒鐘。


ESLint 設定檔:看懂它在幹嘛

新版設定:eslint.config.js(ESLint 9+)

// eslint.config.js
import js from '@eslint/js';
import react from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';

export default [
  js.configs.recommended,              // 基本 JS 規則
  {
    plugins: {
      react,                           // React 專用規則
      'react-hooks': reactHooks        // Hooks 使用規則
    },
    rules: {
      'react-hooks/rules-of-hooks': 'error',      // Hook 必須正確使用
      'react-hooks/exhaustive-deps': 'warn',      // useEffect 依賴要完整
      'no-unused-vars': 'warn'                    // 沒用到的變數會警告
    }
  }
];
Code language: JavaScript (javascript)

逐段翻譯:

你會看到 意思
js.configs.recommended 套用官方建議的基本規則
plugins: { react } 載入 React 專用檢查
'error' 違反就報錯,CI 會失敗
'warn' 只是警告,CI 不會失敗
'off' 關掉這條規則

舊版設定:.eslintrc.json(ESLint 8 及以前)

{
  "extends": [
    "react-app",
    "react-app/jest"
  ],
  "rules": {
    "no-unused-vars": "warn",
    "react-hooks/exhaustive-deps": "warn"
  }
}
Code language: JSON / JSON with Comments (json)

翻譯: 這是 Create React App 預設的設定,繼承它的規則,再加自己的調整。


常見變化:AI 會這樣寫

變化 1:只檢查特定資料夾

- run: npm run lint -- --dir src

翻譯: 只檢查 src 資料夾的檔案(不檢查 node_modules、config 等)。

變化 2:檢查完自動修復

- run: npm run lint -- --fix

翻譯: ESLint 會自動修正能修的問題(如排版、引號風格)。

注意: 在 CI 裡通常不加 --fix,因為你不希望 CI 自己改你的 code。

變化 3:搭配 TypeScript

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      - run: npm ci
      - run: npm run lint
      - run: npm run type-check    # 多一步:檢查 TypeScript 型別
Code language: PHP (php)

翻譯: 先跑 ESLint,再跑 TypeScript 型別檢查,兩個都過才算成功。

變化 4:完整的品質檢查 workflow

name: Code Quality

on:
  push:
    branches: [main, develop]
  pull_request:

jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Run Prettier Check
        run: npm run format:check

      - name: Run Tests
        run: npm test -- --coverage --watchAll=false
Code language: JavaScript (javascript)

翻譯: 一次跑完 ESLint + Prettier + 測試,全部通過才算成功。


package.json 裡的 scripts

你會在 package.json 看到這些:

{
  "scripts": {
    "lint": "eslint src",
    "lint:fix": "eslint src --fix",
    "format": "prettier --write src",
    "format:check": "prettier --check src",
    "type-check": "tsc --noEmit"
  }
}
Code language: JSON / JSON with Comments (json)
指令 意思
npm run lint 檢查程式碼風格
npm run lint:fix 檢查並自動修正
npm run format 用 Prettier 格式化
npm run format:check 只檢查格式,不修改
npm run type-check 檢查 TypeScript 型別

CI 裡通常用: lintformat:checktype-check(只檢查,不修改)。


常見 ESLint 錯誤與修正

錯誤 1:React Hook 順序問題

error  React Hook "useState" is called conditionally  react-hooks/rules-of-hooks
Code language: JavaScript (javascript)

問題:

// 錯誤:條件式裡用 Hook
if (condition) {
  const [value, setValue] = useState(0);
}
Code language: JavaScript (javascript)

修正:

// 正確:Hook 要在最上層
const [value, setValue] = useState(0);
if (condition) {
  // 使用 value
}
Code language: JavaScript (javascript)

錯誤 2:useEffect 缺少依賴

warning  React Hook useEffect has a missing dependency: 'userId'  react-hooks/exhaustive-deps
Code language: JavaScript (javascript)

問題:

useEffect(() => {
  fetchUser(userId);
}, []);  // 缺少 userId
Code language: JavaScript (javascript)

修正:

useEffect(() => {
  fetchUser(userId);
}, [userId]);  // 加上 userId
Code language: JavaScript (javascript)

錯誤 3:未使用的變數

warning  'unusedVar' is assigned a value but never used  no-unused-vars
Code language: JavaScript (javascript)

修正: 刪掉沒用到的變數,或者如果是刻意的,用底線開頭:

const _intentionallyUnused = something;
Code language: JavaScript (javascript)

Vibe Coder 檢查點

看到前端 CI workflow 時確認:

  • [ ] 有用 npm ci 而不是 npm install 嗎?
  • [ ] 有設定 cache: 'npm' 加速嗎?
  • [ ] Node 版本和專案一致嗎?(看 package.json 的 engines)
  • [ ] ESLint 設定檔存在嗎?(eslint.config.js 或 .eslintrc.json)
  • [ ] package.json 有定義 lint script 嗎?

知道就好:進階設定

這些遇到再查:

  • ESLint 共用設定:eslint-config-airbnb、eslint-config-standard 等預設規則包
  • Monorepo 設定:workspaces 裡怎麼設定 ESLint
  • 自訂規則:怎麼寫自己的 ESLint rule
  • ESLint + Editor:VSCode 整合即時提示

完整範例專案結構

my-react-app/
├── .github/
│   └── workflows/
│       └── lint.yml           # CI workflow
├── src/
│   ├── App.jsx
│   └── components/
├── eslint.config.js           # ESLint 設定
├── package.json               # 包含 lint script
└── package-lock.json          # 鎖定依賴版本
Code language: PHP (php)

下一步

這篇學會了前端 CI 的基本設定。下一篇會教你:

  • 後端 Python 專案的 CI 設定
  • pytest + flake8/ruff 自動化
  • requirements.txt 依賴管理

重點回顧

概念 一句話記憶
npm ci CI 專用安裝,比 npm install 快且嚴格
cache: ‘npm’ 快取依賴,加速 CI
eslint.config.js ESLint 9+ 的設定檔
‘error’ / ‘warn’ / ‘off’ 規則嚴重程度,error 會讓 CI 失敗
react-hooks/rules-of-hooks 檢查 Hook 使用順序
react-hooks/exhaustive-deps 檢查 useEffect 依賴完整性

進階測驗:前端自動化 React + ESLint 程式碼品質檢查

測驗目標:驗證你是否能在實際情境中應用所學。
共 5 題,包含情境題與錯誤診斷題。

1. 你正在設定團隊的前端 CI workflow,希望加速重複執行的時間。目前 workflow 每次執行都要花 3 分鐘安裝依賴。你應該怎麼做? 情境題

  • A. 把 npm ci 改成 npm install
  • B. 在 actions/setup-node 加入 cache: 'npm'
  • C. 移除 package-lock.json 檔案
  • D. 使用 npm install --legacy-peer-deps

2. 團隊的 CI 執行時出現以下錯誤,最可能的原因是什麼? 錯誤診斷

error React Hook “useState” is called conditionally react-hooks/rules-of-hooks
  • A. 忘記 import useState
  • B. useEffect 的依賴陣列不完整
  • C. 在條件式或迴圈中使用了 useState
  • D. useState 的初始值格式錯誤

3. 你的 React + TypeScript 專案需要同時檢查 ESLint 規則和 TypeScript 型別。你應該如何設定 CI workflow? 情境題

  • A. 只執行 npm run lint,ESLint 會自動檢查型別
  • B. 只執行 npm run type-check,TypeScript 會自動檢查 ESLint 規則
  • C. 執行 npm run lint -- --fix && npm run type-check
  • D. 依序執行 npm run lintnpm run type-check

4. 同事執行 CI 時看到以下警告,他應該如何修正? 錯誤診斷

warning React Hook useEffect has a missing dependency: ‘userId’ react-hooks/exhaustive-deps // 問題程式碼 useEffect(() => { fetchUser(userId); }, []);
  • A. 在 ESLint 設定中把這條規則關掉
  • B. 把 userId 加入依賴陣列 [userId]
  • C. 把 useEffect 改成 useLayoutEffect
  • D. 在 useEffect 內部宣告 userId 變數

5. 你想讓 CI 在檢查格式時只「檢查」而不「修改」檔案,以下哪個 package.json scripts 設定是正確的? 情境題

{ “scripts”: { “format”: “prettier –write src”, “format:check”: “prettier –check src” } }
  • A. CI 中執行 npm run format
  • B. CI 中執行 npm run format -- --dry-run
  • C. CI 中執行 npm run format:check
  • D. CI 中執行 npm run format -- --no-write

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *