開始接手公司前端專案時發現沒有程式碼相關的規範,光是這樣已經可以預見後續維護專案會有多痛苦了,於是我提出將 ESLint、Prettier 等工具導入前端專案,考慮到初期導入成本我們團隊最終討論會以現有網路上的規範使用 Airbnb 進行,未來再以開發過程的回饋補足其他缺少的規範。 目前專案都是以 Vite 作為建置工具,Vite 在這方面的生態也減少了導入這些工具的成本 ,我在下方的文件統整了整合、配置、規則、常見問題這些常見的需求,同時也向團隊提起會議來介紹導入工具的優劣。
目錄
前提須知
開啟 VS Code 專案後,請先確保有以下插件,以及專案內有設置 ESLint 相關配置(eslint.config.js、.prettierrc.json)。如尚未看到,請先詢問專案參與者,或參考 ESLint 官方入門文件。
必裝插件
- Prettier - Code formatter (
esbenp.prettier-vscode) - ESLint (
dbaeumer.vscode-eslint)
工具職責釐清
在進入配置前,我們先簡單釐清這兩者的關係:
| 工具 | 職責 | 處理內容 |
|---|---|---|
| Prettier | 程式碼格式化 | 縮排、單雙引號、分號、換行等「視覺排版」問題 |
| ESLint | 程式碼品質檢查 | 變數定義、邏輯錯誤、React Hooks 規範等「代碼品質」問題 |
團隊協作建議
我們可以在本地專案設置.vscode資料夾並添加以下兩種檔案 :
這種方式可以讓所有專案參與者都共用同一個配置檔,確保團隊在開發上能有一致性。
settings.json: 常見的editor.formatOnSave等等參數。extensions.json: 使用VS code 時用於建議需要安裝的extnesion插件提示。我們也能在專案設置
.prettierrc.json讓所有人在 Format 的開發上的格式化一致 !
{
"tabWidth": 4,
"singleQuote": false,
"bracketSpacing": false
}整合指南
在專案中會看到兩支配置檔分別是 eslint.config.js 和 .prettierrc.json,這是由官方建議的檔名,VS Code 插件也會自動讀取這些配置檔案。
Prettier 配置檔
此配置檔可讓 VS Code 或透過 npm 套件的方式讀取格式化規則。
{
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "all",
"printWidth": 80,
"endOfLine": "lf"
}Prettier 配置參數說明
| 參數名稱 | 預設值 | 推薦值 / 可選值 | 中文功能說明 |
|---|---|---|---|
tabWidth | 2 | 2 或 4 | 每個縮進層級的空格數量。 |
semi | true | true 或 false | 是否在每條語句的末尾加上分號。 |
singleQuote | false | true 或 false | 是否使用單引號代替雙引號。 |
trailingComma | "all" | "all"、"es5" 或 "none" | 多行結構(如物件、陣列)中末尾逗號的列印策略。 |
printWidth | 80 | 80、100 或 120 | 每行代碼的最大長度,超過此長度會自動換行。 |
useTabs | false | true 或 false | 是否使用 Tab 鍵而非空格進行代碼縮進。 |
bracketSpacing | true | true 或 false | 是否在物件字面量的括號內側加上空格(例如:{ foo: bar })。 |
arrowParens | "always" | "always" 或 "avoid" | 箭頭函數只有一個參數時是否加上圓括號(如 x => x)。 |
endOfLine | "lf" | "lf" 或 "auto" | 強制統一換行符號(避免跨平台開發時因 CRLF/LF 報錯)。 |
singleAttributePerLine | false | true 或 false | 在 HTML/JSX 中,是否強制將每個屬性(Attribute)都單獨放一行。 |
ESLint 配置檔
以下示範使用 Airbnb 規範制定。
import js from '@eslint/js';
import globals from 'globals';
import pluginReact from 'eslint-plugin-react';
import { FlatCompat } from '@eslint/eslintrc';
import path from 'path';
import { fileURLToPath } from 'url';
// 模擬 __dirname (Flat Config 必備)
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const compat = new FlatCompat({
baseDirectory: __dirname,
});
export default [
// 1. 繼承 Airbnb 的 React 規範 (包含 hooks, jsx-a11y 等)
...compat.extends('eslint-config-airbnb'),
// 2. 繼承 React 套件的推薦 Flat 設定
pluginReact.configs.flat.recommended,
{
files: ['**/*.{js,jsx,mjs,cjs}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
},
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
// 3. 自定義規則 (Airbnb 真的很嚴,你可以在這裡關掉不喜歡的)
rules: {
'react/react-in-jsx-scope': 'off', // React 17+ 不需要 import React
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
'no-console': 'warn',
},
},
];規則等級設置
"off"或0- 關閉規則"warn"或1- 只用於提示訊息(VS Code 的 ESLint 提示),不會讓編譯中斷"error"或2- 強制遵守規則,編譯過程會中斷
透過制定多項規則範圍來題來可讀性
ESLint Flag config在於每個配置都屬於扁平化的物件設計,相當於我們每制定一個rules都可以是單獨的物件,並且指定範圍。
舉例來說我可能 規則1 只想套用 A.jsx ,而 規則2 想套用在 B.jsx,那我們可以這樣做 :
import { defineConfig } from 'eslint/config';
export default defineConfig([
// 規則 1
{
files: ['**/A.jsx'],
rules: {
semi: ['error', 'always'],
},
},
// 規則 2
{
files: ['**/B.jsx'],
rules: {
'no-console': 'error',
},
},
]);我們來做進階一點的操作 ! 依照規則功能分類在不同區塊來提高整體可讀性,我們可以簡單區分為 :
- 通用類規則
- 樣式規則
- React 規則
- React hooks 規則 並將各類規則各自獨立於 Object 上
// 通用規則(Core Rules)
const coreRules = {
'no-console': 'warn',
'no-debugger': 'warn',
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'prefer-const': 'error',
'no-var': 'error',
eqeqeq: ['error', 'always'],
};
// React 規則
const reactRules = {
'react/react-in-jsx-scope': 'off',
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx'] }],
'react/prop-types': 'warn',
'react/no-array-index-key': 'warn',
};
// React Hooks 規則
const hooksRules = {
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
};
// 樣式規則(Coding styles)
const styleRules = {
semi: ['error', 'always'],
quotes: ['error', 'single', { avoidEscape: true }],
indent: ['error', 2],
'no-trailing-spaces': 'error',
};
export default [
...compat.extends('eslint-config-airbnb'),
pluginReact.configs.flat.recommended,
{
files: ['**/*.{js,jsx,mjs,cjs}'],
languageOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
globals: {
...globals.browser,
},
parserOptions: {
ecmaFeatures: {
jsx: true,
},
},
},
rules: {
...coreRules,
...reactRules,
...hooksRules,
...bestPracticesRules,
...styleRules,
},
},
];針對特定檔案調整規則
當團隊有新規則加入想暫時使用,或某些規則 plugin 會誤判時,可使用以下方法:
方法一:直接在 eslint.config.js 調整
{
rules: {
"no-console": "error"
}
}方法二:透過內聯註解調整(推薦)
- 整個檔案調整規則
import React from 'react';
/* eslint no-console: "off" */
console.log('newbie');- 使用單行調整規則
import React from 'react';
console.log('Hello'); /* eslint-disable-line no-console */- 使用下行調整規則
import React from 'react';
/* eslint-disable-next-line no-console */
console.log('Hello');規則重複設置
當設置多條規則物件時,遇到相同規則會以最後一個為基準:
import { defineConfig } from 'eslint/config';
export default defineConfig([
{
rules: {
semi: ['error', 'never'],
},
},
{
rules: {
semi: ['warn', 'always'], // 以此為準
},
},
]);編譯檢查 or 手動檢查
配置完成後,可選擇以下幾種方式檢查規則:
將 ESLint 整合進 Vite 編譯流程
使用 vite-plugin-eslint 插件,開發過程中若違反規則會直接編譯失敗並跳出錯誤訊息。
npm i -D vite-plugin-eslintimport react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import eslint from 'vite-plugin-eslint';
export default defineConfig({
plugins: [react(), eslint()],
});接下來你就會開始經歷地獄級的開發挑戰。
使用 package.json 的 scripts 來整合
在 scripts 中自訂檢查指令或在打包時同時檢查。以下設置會在 build 時先檢查規則,若失敗將不會繼續打包(Exit code)。
{
"scripts": {
"build": "npm run lint && vite build",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
}
}npm run build # 檢查並打包
npm run lint # 只檢查規則
npm run lint:fix # 檢查並自動修復使用 Command Line 檢查
直接在終端執行檢查命令: 來源
# 檢查所有檔案
npx eslint .
# 檢查特定檔案
npx eslint src/App.jsx
# 檢查多筆檔案
npx eslint a.jsx b.jsx
# 檢查並自動修復
npx eslint . --fix常見問題
ESLint 中文化(建議別點進來)
就知道你會點進來 : ) 失望吧,沒這東西 目前官方沒有明確提供自訂錯誤訊息及中文提示,除非自行撰寫規則。 參考資源:
- ESLint 官方規則查詢 - 查看規則相關解釋
- VS Code ESLint 中文翻譯插件 - 簡體中文翻譯(缺點是非繁體中文)
- 官方討論 Issue - 探討自訂檢查訊息的可能性
來看看閣下透過
VS Code ESLint翻譯插件會怎麼翻譯 :
我想避免 Prettier 格式化某些檔案
建立 .prettierignore 檔案,使用與 .gitignore 相同的語法。
# Test Folder:
build
coverage
# 天下大亂:
**/*.jsx.prettierignore 預設忽視的檔案:
**/.git
**/.svn
**/.hg
**/node_modules我想指定或忽略某些檔案被 ESLint 處理
方案一:全局忽略配置(globalIgnores)
官方提供 globalIgnores 方法,在陣列中寫入匹配的正則:
import { defineConfig, globalIgnores } from 'eslint/config';
export default defineConfig([
globalIgnores(['**/*.js', '**/*.cjs', '**/*.mjs']),
]);預設會忽略 ["**/node_modules/", ".git/"] 檔案。ESLint 預設模式下會檢查 **/*.js、**/*.cjs 和 **/*.mjs。
補充: 當只想檢查非 .js 的檔案時,必須在 globalIgnores 中也寫入 .js 檔案,否則 ESLint 還是會同時檢查預設配置。
import { defineConfig, globalIgnores } from 'eslint/config';
export default defineConfig([
globalIgnores(['**/*.js', '**/*.cjs', '**/*.mjs']),
{
files: ['**/*.ts'],
rules: {
/* ... */
},
},
]);方案二:反向全局配置(UnglobalIgnores)
當設置忽略全局後但想讓某個資料夾底下的檔案檢查 ESLint,可使用反向配置:
假設想忽略 **/Test/** 底下所有檔案,但 Test 底下還有個 Test_2 資料夾想特別檢查:
{
globalIgnores(['**/Test/**', '!**/Test/', '!**/Test/Test_2/**']);
}解釋: 這就像剝洋蔥一層一層剝落:
**/Test/**- 忽略 Test 底下所有檔案!**/Test/- 解除 Test 資料夾本身的忽略(讓 ESLint 重新進入檢查)!**/Test/Test_2/**- 解除 Test/Test_2 底下所有內容的忽略 若直接指定路徑會無法生效,因為沒有先解除上一層的外殼。
方案三:局部忽略
指定檢查特定區域的檔案時使用 ignores:
{
files: ["**/*.{js,jsx,mjs,cjs}"],
ignores: ["**/Test/**"],
rules: { /* ... */ }
}指定此規則會檢查 files 這些,但不要檢查 Test 底下所有檔案。
注意: 當規則物件只有 ignores 欄位時(除了 name 外,用於提示 linter 錯誤來源),會被當作全局忽略配置來看。
小補充: globalIgnores 和局部 ignores 的寫法略有差異:
// globalIgnores - 忽略 Test 及其以下所有檔案
globalIgnores(['**/Test']);
// 局部 ignores - 需要額外指定位置
{
ignores: ['**/Test/*'];
}「存檔時自動修復」發生格式化衝突
問題產生的原因在 VS Code 的 setting.json 中同時指定了兩種不同的格式化方式(ESlint、Prettier)。
例如 Airbnb 風格會有分號,而 Prettier 風格則沒有,觸發 Format 後就會發生一下有一下沒有的情況。
{
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
}
}當設置上述配置時,會同時執行 Prettier 和 ESLint 修正,執行順序通常為 Prettier → ESLint(因為 ESLint 需經歷 AST 語法解析)。
解決方案
推薦方案:使用 eslint-config-prettier(最佳做法) 使用 eslint-config-prettier 關閉 ESLint 中所有與排版相關的規則。此套件會關閉與 ESLint 衝突的規則,實現職責分離。
npm i -D eslint-config-prettierimport prettierConfig from 'eslint-config-prettier';
export default [
...someConfig, // 其他配置檔
prettierConfig,
];完成!現在 Formatter 專注於優化排版,Linter 專注於檢查程式碼風格。 替代方案一:控制執行順序
{
"editor.formatOnSave": false,
"editor.codeActionsOnSave": {
"source.fixAll.prettier": "explicit",
"source.fixAll.eslint": "explicit"
}
}檔案儲存後會依序觸發:source.fixAll.prettier → source.fixAll.eslint
替代方案二:關閉自動格式化 ( 我相信你不會這樣做的 )
{
"editor.formatOnSave": false
}知識小補充
Prettier Resolution
你可能會好奇為什麼既有 VS Code 的 setting.json 配置,還要有 .prettierrc.json 配置檔?
答案是:VS Code 的 Prettier 會優先使用配置檔的順序如下:
本地專案 → 全域模組 (Global Modules) → 插件內建版本 (Bundled Version)
此動作稱之「Prettier Resolution」。VS Code 的 setting.json 其實也遵循相同原理,只要在專案設置 .vscode/setting.json 就會被優先讀取。
各階段說明:
- 本地專案 - 本地專案根目錄的
.prettierrc.json - 全域模組 (Global Modules) - 若本地找不到,且
setting.json中開啟了prettier.resolveGlobalModules: true,會檢查電腦系統環境(全域)是否安裝 Prettier - 插件內建版本 (Bundled Version) - 若前兩處都找不到,插件會使用內建打包的 Prettier 版本
editor.codeActionsOnSave vs editor.formatOnSave 差別
codeActionsOnSave 的涵義為「Quick Fixes and refactorings」,能為你做兩件事:
- 快速修正程式碼
- 重新結構化程式碼 常見配置示例:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.sortImports": "explicit"
}
}這說明當儲存檔案後會:
- 透過 ESLint 快速修正目前語法規則
- 重新排序檔案最上方
import的順序 (A-Z) formatOnSave 的涵義為「儲存檔案後觸發 Formatter 格式化功能」:
{
"editor.formatOnSave": true
}重要提示
editor.codeActionsOnSave 的值你可能會看到有人設置 true 或 false。雖然目前在 VS Code 還有作用,但未來將移除,取而代之的設置值為:
- explicit(預設)- 當做
明確的儲存操作時觸發(Ctrl+S、Cmd+S),自動儲存不觸發 - always - 每次有儲存時都觸發
- never - 永遠不觸發
結論:
codeActionsOnSave讓你客製化儲存檔案後想執行的一連串動作,而formatOnSave只是單純幫你格式化文件。 官方來源