Skip to main content

[Note] ESLint & Prettier

ESLint

ESLint Demo

簡介

ESLint 是一個用來檢查 JavaScript (也支援 TypeScript、React 等)的靜態程式碼檢查工具 (Linter),幫助開發者維持一致的程式碼風格和品質、協助檢查程式碼的錯誤和減少潛在問題。

主要功能

  • 程式碼錯誤偵測(例如忘記加 ;、變數未定義)
  • 程式碼風格檢查(如單引號 ' 與雙引號 " 的使用、tab 與 space)
  • 自動修復常見問題( eslint --fix
  • 支援自訂規則與插件擴充

核心概念

  • 規則 Rules:ESLint 的核心,定義了程式碼檢查的標準。每個規則都有一個唯一的名稱和對應的配置選項。
  • 插件 Plugins:擴展 ESLint 的工具,可以添加新的規則、解析器、報告器等。
  • 共享配置 Shareable Configs:包含一系列預定億的規則和配置,便於共享和重用。

ESLint CLI

# 安裝 ESLint
$ npm init @eslint/config@latest
$ pnpm create @eslint/config@latest

# Run ESLint: npx eslint [options] [file|dir|glob]*
$ npx eslint # 檢查所有檔案,等同於 npx eslint .
$ npx eslint yourfile.js
$ npx eslint file1.js file2.js
$ npx eslint "lib/**"
$ pnpm dlx eslint yourfile.js

# Debug
$ npx eslint --debug file.js
$ npx eslint --print-config file.js # 使用時機:當你不確定為什麼 linting 沒有產生預期的結果
$ npx eslint --inspect-config # 使用時機:當你不確定某個檔案是否有套用到特定的 configuration object

# Fix
$ npx eslint --fix

Configuration 設定檔

Configure ESLint

tip

ESLint v9 引入 **Flat Config(扁平設定)**成為預設格式,是目前最推薦的設定方式,取代傳統的 .eslintrc 系列設定檔。

執行 npm init @eslint/config 後會自動生成 ESLint 的設定檔。有兩種主要格式:

  1. 舊格式:Legacy Config(階層式設定)

    • 檔案名稱.eslintrc.js.eslintrc.json.eslintrc.yaml.eslintrc.yml...
    • 特色:階層式(hierarchical)設定,設定分散在多個檔案,會從專案目錄往上尋找並合併多層設定
    • 問題:設定覆蓋行為複雜,難以追蹤最終規則來源
  2. 新格式:Flat Config(扁平式設定)- ESLint v9+

    • 檔案名稱eslint.config.jseslint.config.mjseslint.config.cjs...
    • 特色:單一設定檔,扁平化陣列結構,順序決定優先級,更直覺可控
    • 優勢:每個元素是一個設定物件,所有設定集中處理、使用 ES modules、支援可編程設定

Flat Config

Flat Config 是一個由設定物件 (configuration objects) 所組成的陣列,放置於專案根目錄 (root):

eslint.config.js
export default [
// 設定物件 1
{
files: ['**/*.js'],
rules: {
/* 規則 */
},
},

// 設定物件 2
{
files: ['**/*.ts'],
rules: {
/* 規則 */
},
},

// ... 更多設定物件
];

匯出方式

Export 一定要是 ESM 格式 (export default)。Flat Config 支援兩種匯出方式:

  1. 直接匯出陣列 (export default [ ... ] )

    eslint.config.js
    import js from '@eslint/js';

    export default [
    js.configs.recommended,
    {
    files: ['**/*.js'],
    rules: {
    'no-console': 'warn',
    },
    },
    ];
  2. 使用 defineConfig() helper(官方建議的最佳實踐)

    eslint.config.js
    import { defineConfig } from 'eslint/config';
    import js from '@eslint/js';

    export default defineConfig([
    js.configs.recommended,
    {
    files: ['**/*.js'],
    rules: {
    'no-console': 'warn',
    },
    },
    ]);

Configuration Objects 設定物件

Configuration Objects

每個設定物件定義了一組規則和其適用範圍,包含以下欄位:

核心欄位

欄位類型說明範例
namestring設定物件的名稱(用於 debug)"TypeScript files"
filesstring[]適用的檔案匹配模式(glob pattern)['**/*.ts', '**/*.tsx']
ignoresstring[]排除的檔案匹配模式(glob pattern)['node_modules/**', 'dist/**']

語言設定相關

欄位類型說明範例
languageOptionsobject語言解析設定{ parser, parserOptions, globals }
languageOptions.parserobject程式碼解析器@typescript-eslint/parser
languageOptions.parserOptionsobject解析器選項{ ecmaVersion: 'latest' }
languageOptions.globalsobject全域變數定義globals.browser

規則相關

欄位類型說明範例
extendsobject允許套用現成的規則集,可以是官方或是第三方的{ 'react-hooks': reactHooks }
pluginsobject引入外部規則插件(如 react, prettier){ 'react-hooks': reactHooks }
rulesobject啟用的規則,可以覆蓋 extends 或 plugins{ 'no-console': 'warn' }
settingsobject提供 plugin 共用的設定{ react: { version: 'detect' } }

其他設定

欄位類型說明範例
processorstring or object檔案處理器用於處理非 JS 檔案(如 Markdown)

設定物件執行順序

在 Flat Config 中,陣列順序決定設定的優先級

  1. 後面的設定會覆蓋前面的設定
  2. 相同檔案匹配時,後面的規則優先
  3. Prettier 設定通常放在最後,確保格式規則不被覆蓋
export default [
js.configs.recommended, // 1. 基本規則
tsConfig, // 2. TypeScript 規則(可能覆蓋基本規則)
reactConfig, // 3. React 規則(可能覆蓋前面規則)
prettierConfig, // 4. Prettier 規則(最後執行,避免衝突)
];

Rules 規則

規則是 ESLint 的核心,每個規則控制一個特定的程式碼檢查

"規則名稱""狀態"
  • 每個規則有一個唯一的名稱,例如 "no-alert""no-console"
  • 每個規則有三種狀態: "off"(0,關閉)、"warn"(1,警告)或 "error"(2,錯誤)
  • 某些規則還支援額外參數,如 "indent": ["error", 2] 設定縮排為 2 個空格。
規則狀態
{
rules: {
// 字串格式
'no-console': 'off', // 關閉規則
'no-alert': 'warn', // 警告等級
'no-debugger': 'error', // 錯誤等級

// 數字格式(等價)
'no-console': 0, // 關閉
'no-alert': 1, // 警告
'no-debugger': 2, // 錯誤

// 陣列格式(含參數)
'indent': ['error', 2], // 縮排 2 空格
'quotes': ['error', 'single'], // 使用單引號
'max-len': ['warn', { code: 100 }], // 最大行長度 100
}
}
常用規則範例
{
rules: {
// 程式碼品質
'no-unused-vars': 'error',
'no-undef': 'error',
'no-console': 'warn',

// 程式碼風格
'indent': ['error', 2],
'quotes': ['error', 'single'],
'semi': ['error', 'always'],

// TypeScript 特定規則
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/consistent-type-imports': 'error',

// React 特定規則
'react/jsx-uses-react': 'off',
'react/react-in-jsx-scope': 'off',
}
}

eslint.config.js 完整設定檔範例

eslint.config.js
import { defineConfig } from 'eslint/config';
import js from '@eslint/js';
import ts from '@typescript-eslint/eslint-plugin';
import parserTs from '@typescript-eslint/parser';
import prettier from 'eslint-plugin-prettier/recommended';
import globals from 'globals';

// 一定要是 ESM 格式 (export default)
export default defineConfig([
// 🟡 全域排除設定(不針對特定檔案)
{
name: 'Global ignores',
ignores: [
'node_modules',
'dist',
'build',
'coverage',
'public/mockServiceWorker.js',
],
},

// 🟢 JavaScript 基本規則(官方 js.configs.recommended)
{
...js.configs.recommended,
name: 'JavaScript base rules',
files: ['**/*.js', '**/*.jsx'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
...globals.node,
},
},
rules: {
...js.configs.recommended.rules,
'no-console': 'warn',
'no-debugger': 'error',
},
},

// 🔵 TypeScript 支援 + ESLint plugin
{
name: 'TypeScript rules',
files: ['**/*.ts', '**/*.tsx'],
languageOptions: {
parser: parserTs,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
project: './tsconfig.json',
ecmaFeatures: {
jsx: true,
},
},
globals: globals.browser,
},
plugins: {
'@typescript-eslint': ts,
},
rules: {
...ts.configs.recommended.rules,
'@typescript-eslint/no-unused-vars': ['warn'],
'@typescript-eslint/consistent-type-imports': [
'error',
{ prefer: 'type-imports' },
],
},
},

// ✨ Prettier 整合(格式錯誤會報錯)
{
files: ['**/*.{js,ts,tsx,jsx,json,md}'],
plugins: {
prettier,
},
rules: {
'prettier/prettier': 'error',
},
},

// 🔶 範例:特定檔案(如 test)使用 override 規則
{
name: 'Test files overrides',
files: ['**/*.test.{js,jsx,ts,tsx}', '**/*.spec.{js,jsx,ts,tsx}'],
rules: {
'@typescript-eslint/no-explicit-any': 'off', // 在測試檔案允許 any
'no-console': 'off',
},
},

// 🔸 範例:Markdown 檔案避免不必要的 lint
{
files: ['**/*.md'],
languageOptions: {
parser: undefined,
},
rules: {},
},
]);

忽略規則

忽略所有規則

忽略整個檔案:

// 放在檔案的最上方
/* eslint-disable */

忽略單行:

alert('foo'); // eslint-disable-line no-alert, quotes, semi

// eslint-disable-next-line no-alert
alert('foo');

忽略多行:

/* eslint-disable */
alert('foo');
/* eslint-enable */

忽略特定規則

忽整個檔案:

// 放在檔案的最上方
/* eslint-disable [rule-name] */
/* eslint-disable no-alert, no-console

忽略單行:

alert('foo'); // eslint-disable-line no-alert, quotes, semi

// eslint-disable-next-line no-alert
alert('foo');

忽略多行:

/* eslint-disable no-alert, no-console */
alert('foo');
console.log('bar');
/* eslint-enable no-alert, no-console */

ESLint + Prettier

Prettier

Prettier 是一個 code formatter 自動排版工具,常與 ESLint 互相搭配使用:

  1. ESLint 負責邏輯與程式問題檢查
  2. Prettier 負責格式排版(縮排、引號、括號)

套件安裝建議

# 基本 Prettier 安裝
$ npm install --save-dev --save-exact prettier

# ESLint + Prettier 整合套件
$ npm install --save-dev eslint-plugin-prettier eslint-config-prettier

# 推薦方式:使用 eslint-plugin-prettier/recommended (Flat Config)
$ npm install --save-dev eslint-plugin-prettier

套件說明:

info

Configuration (new: eslint.config.js) For flat configuration, this plugin ships with an eslint-plugin-prettier/recommended config that sets up both eslint-plugin-prettier and eslint-config-prettier in one go.

使用 eslint-plugin-prettier/recommended + Flat Config 就能讓 ESLint 處理格式錯誤並且避免衝突

eslint.config.ts 加上:

import eslintPluginPrettier from 'eslint-plugin-prettier/recommended';
...

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
...
}
).concat(eslintPluginPrettier);

Prettier CLI

# 安裝 Prettier
$ npm install --save-dev --save-exact prettier

# 建立設定檔:.prettierrc
$ node --eval "fs.writeFileSync('.prettierrc','{}\n')"

# 建立忽略檔:.prettierignore
$ node --eval "fs.writeFileSync('.prettierignore','# Ignore artifacts:\nbuild\ncoverage\n')"

# 執行 prettier 排版
$ npx prettier . --check # 只檢查,不覆寫
$ npx prettier --write . # 全部檔案,或
$ pnpm exec prettier --write .
$ npx prettier --write app/ # 針對特定目錄
$ npx prettier --write app/components/Button.js # 針對特定檔案
$ npx prettier --write "app/**/*.test.js" # 針對匹配的全域路徑(glob)

.prettierrc 設定檔範例

{
"semi": true,
"singleQuote": true,
"printWidth": 100,
"tabWidth": 2,
"trailingComma": "all",
"bracketSpacing": true,
"arrowParens": "avoid",
"endOfLine": "lf",
"plugins": ["prettier-plugin-tailwindcss"]
}

常用設定值

設定項目類型常用值 / 範例說明
semibooleantrue / false是否在句尾加上分號 ;(預設 true
singleQuotebooleantrue / false使用單引號 ' 而不是雙引號 "
printWidthnumber80 / 100 / 120每行最大寬度(預設 80)
tabWidthnumber2 / 4縮排空格數(預設 2)
useTabsbooleantrue / false使用 tab (\t) 而不是空格
trailingCommastring"none" / "es5" / "all"尾端逗號:none: 不加es5: 只加在 ES5 支援的地方all: 所有可能的地方(建議)
bracketSpacingbooleantrue / false物件 { foo: bar } 是否有空格
arrowParensstring"avoid" / "always"箭頭函式參數是否總是加括號:
avoid: 只有一個參數時省略括號
always: 總是
endOfLinestring"lf" / "crlf" / "auto"換行字元格式,建議使用 "lf"(Unix/macOS)
pluginsarray["prettier-plugin-tailwindcss"]使用外掛(如 TailwindCSS class 排序)
embeddedLanguageFormattingstring"auto" / "off"是否格式化嵌入的程式碼,如 markdown 裡的 code block

ESLint 常用 Plugin/Config 整合建議

React

  • eslint-plugin-react:檢查 React 基本規則
  • eslint-plugin-react-hooks:檢查 React Hooks 用法規則(如依賴清單)
  • eslint-plugin-jsx-a11y:檢查 JSX 無障礙(a11y)問題

TypeScript

  • @typescript-eslint/eslint-plugin:TypeScript 專用 ESLint 規則
  • @typescript-eslint/parser:TypeScript 解析器

程式碼品質與風格

  • eslint-plugin-import:檢查 Import/Export 語句與排序
  • eslint-config-airbnb:Airbnb JavaScript 程式碼風格
  • eslint-config-airbnb-typescript:Airbnb TypeScript 程式碼風格
  • @next/eslint-config-next:Next.js 官方規則

搭配 package.json 腳本

新增 lint 指令:

package.json
{
// ...
"scripts": {
// ....
"lint": "eslint . --ext .js,.jsx,.ts,.tsx",
"lint-fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
"prettier": "npx prettier --write ."
}
}

輸入指令,執行腳本:

$ npm run lint
$ npm run lint-fix
$ npm run prettier

VSCode 整合設定

Prettier - Code formatter

Prettier ESLint Extension

.vscode/settings.json 加入

{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"eslint.validate": [
"javascript",
"typescript",
"javascriptreact",
"typescriptreact"
]
}

整合 Git Hooks: Husky & lint-staged

Pre-commit Hook

整合 Git hooks ,在 CI 階段就自動執行 prettier --write ,確保程式碼在 commit 前 (pre-commit) 都已經被 format 過。

$ npm install --save-dev husky lint-staged
$ npx husky init
$ node --eval "fs.writeFileSync('.husky/pre-commit','npx lint-staged\n')"

將 lint-staged 加到 package.json

{
"lint-staged": {
"**/*": "prettier --write --ignore-unknown"
}
}