什么是 ESLint #
ESLint 是一个开源的 JavaScript 代码检查工具,用于识别和报告代码中的模式问题,帮助开发者:
- 🔍 发现问题:找出潜在的错误和 bug
- 📏 统一风格:强制执行一致的代码风格
- ⚡ 自动修复:自动修复可修复的问题
- 🔧 高度可配置:支持自定义规则和插件
- 🚀 现代化:支持 ES6+、TypeScript、JSX 等
# 安装 ESLint
npm install --save-dev eslint
# 初始化配置文件(ESLint 8.x)
npx eslint --init注意:本文档基于 ESLint 8.x 版本(已于 2024-10-05 停止维护),建议新项目使用 ESLint 9.x。
配置文件 #
ESLint 8.x 支持多种配置文件格式:
# JavaScript 格式(推荐)
.eslintrc.js
.eslintrc.cjs
# JSON 格式
.eslintrc.json
.eslintrc
# YAML 格式
.eslintrc.yaml
.eslintrc.yml
# package.json 中配置
{
"eslintConfig": {
// 配置项
}
}推荐使用 .eslintrc.js 或 .eslintrc.cjs,本文以 JavaScript 格式为例。
配置文件后缀说明 #
.eslintrc.js vs .eslintrc.cjs #
根据项目的模块系统选择:
1. .eslintrc.js
// .eslintrc.js
module.exports = {
root: true,
env: {
node: true,
browser: true
},
rules: {
'no-console': 'warn'
}
};使用模块系统:
package.json中"type": "commonjs"或未指定 → CommonJSpackage.json中"type": "module"→ ES Module(需要export default)
2. .eslintrc.cjs(ES Module 项目推荐)
// .eslintrc.cjs
module.exports = {
root: true,
env: {
node: true,
browser: true
}
};适用场景:
- 项目
package.json中有"type": "module" - 明确使用 CommonJS 语法
- 避免模块系统混淆
一、核心配置选项 #
1.1 root #
作用:限制 ESLint 向上查找配置文件。
{
"root": true
}默认值:false
影响对比:
// root: false(默认)
// ESLint 会向上查找父目录的配置文件,直到找到 root: true 或到达文件系统根目录
project/
├── .eslintrc.js (root: false)
├── src/
│ └── index.js
└── parent/
└── .eslintrc.js // 也会被应用
// root: true
// ESLint 只使用当前项目的配置,不再向上查找
project/
├── .eslintrc.js (root: true) // 只使用这个
├── src/
│ └── index.js使用建议:
- 项目根目录:
true(推荐) - 子目录覆盖配置:
false
1.2 env #
作用:指定代码运行环境,自动添加对应的全局变量。
{
"env": {
"browser": true, // 浏览器全局变量
"node": true, // Node.js 全局变量
"es2021": true // ES2021 全局变量
}
}常用环境:
{
"env": {
"browser": true, // window, document, localStorage 等
"node": true, // process, __dirname, require 等
"es6": true, // ES6 全局变量(Promise, Set, Map)
"es2020": true, // ES2020 全局变量(BigInt, globalThis)
"es2021": true, // ES2021 全局变量
"es2022": true, // ES2022 全局变量
"worker": true, // Web Worker 全局变量
"serviceworker": true,// Service Worker 全局变量
"commonjs": true, // CommonJS 全局变量(module, exports)
"shared-node-browser": true, // Node.js 和浏览器共享的全局变量
"jest": true, // Jest 全局变量(describe, test, expect)
"mocha": true, // Mocha 全局变量(describe, it, before)
"jquery": true // jQuery 全局变量($, jQuery)
}
}影响对比:
// ❌ 未配置 env.browser
console.log(window.location); // ❌ 错误:'window' is not defined
document.querySelector('.btn'); // ❌ 错误:'document' is not defined
// ✅ 配置 env.browser: true
console.log(window.location); // ✅ 正确
document.querySelector('.btn'); // ✅ 正确
// ❌ 未配置 env.node
console.log(process.env.NODE_ENV); // ❌ 错误:'process' is not defined
const path = require('path'); // ❌ 错误:'require' is not defined
// ✅ 配置 env.node: true
console.log(process.env.NODE_ENV); // ✅ 正确
const path = require('path'); // ✅ 正确1.3 globals #
作用:定义自定义全局变量。
{
"globals": {
"$": "readonly", // jQuery(只读)
"myGlobal": "writable", // 可写全局变量
"MY_CONST": "readonly" // 只读常量
}
}可选值:
"readonly"/"off":只读,不可修改"writable"/"on":可读写
影响对比:
// ❌ 未声明全局变量
console.log(myAPI); // ❌ 错误:'myAPI' is not defined
// ✅ 配置 globals
{
"globals": {
"myAPI": "readonly"
}
}
console.log(myAPI); // ✅ 正确
// readonly vs writable
{
"globals": {
"config": "readonly"
}
}
config = {}; // ❌ 错误:'config' is read-only
{
"globals": {
"config": "writable"
}
}
config = {}; // ✅ 正确1.4 extends #
作用:继承共享配置。
{
"extends": [
"eslint:recommended", // ESLint 推荐规则
"plugin:vue/vue3-recommended", // Vue 3 推荐规则
"plugin:@typescript-eslint/recommended" // TypeScript 推荐规则
]
}常用配置:
{
"extends": [
// ESLint 官方
"eslint:recommended", // 核心推荐规则
"eslint:all", // 所有规则(不推荐)
// Vue
"plugin:vue/vue3-essential", // Vue 3 必要规则
"plugin:vue/vue3-strongly-recommended", // Vue 3 强烈推荐
"plugin:vue/vue3-recommended", // Vue 3 推荐规则(最严格)
// React
"plugin:react/recommended", // React 推荐规则
"plugin:react-hooks/recommended", // React Hooks 规则
// TypeScript
"plugin:@typescript-eslint/recommended", // TS 推荐规则
"plugin:@typescript-eslint/recommended-requiring-type-checking", // 需要类型检查
// Prettier(必须放在最后)
"plugin:prettier/recommended"
]
}配置顺序:后面的配置会覆盖前面的。
{
"extends": [
"eslint:recommended", // 基础规则
"plugin:vue/vue3-recommended", // Vue 规则(可能覆盖基础规则)
"plugin:prettier/recommended" // Prettier 规则(必须最后,禁用冲突规则)
]
}1.5 plugins #
作用:加载第三方插件。
{
"plugins": [
"vue", // eslint-plugin-vue
"@typescript-eslint", // @typescript-eslint/eslint-plugin
"import", // eslint-plugin-import
"prettier" // eslint-plugin-prettier
]
}插件命名规则:
eslint-plugin-前缀可以省略@scope/eslint-plugin-name→@scope/name@scope/eslint-plugin→@scope
影响对比:
// ❌ 未安装/配置插件
{
"rules": {
"vue/no-unused-vars": "error" // ❌ 错误:找不到 vue 插件
}
}
// ✅ 配置插件
{
"plugins": ["vue"],
"rules": {
"vue/no-unused-vars": "error" // ✅ 正确
}
}常用插件:
# Vue
npm install --save-dev eslint-plugin-vue
# TypeScript
npm install --save-dev @typescript-eslint/eslint-plugin @typescript-eslint/parser
# React
npm install --save-dev eslint-plugin-react eslint-plugin-react-hooks
# Import
npm install --save-dev eslint-plugin-import
# Prettier
npm install --save-dev eslint-plugin-prettier eslint-config-prettier1.6 parser #
作用:指定解析器,支持不同的语法。
{
"parser": "@typescript-eslint/parser"
}常用解析器:
// 默认:espree(ESLint 内置)
// 支持标准 JavaScript
// TypeScript
{
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "./tsconfig.json"
}
}
// Vue
{
"parser": "vue-eslint-parser",
"parserOptions": {
"parser": "@typescript-eslint/parser" // 解析 <script> 标签内容
}
}
// Babel
{
"parser": "@babel/eslint-parser",
"parserOptions": {
"requireConfigFile": false
}
}影响对比:
// ❌ 默认解析器无法解析 TypeScript
interface User {
name: string;
} // ❌ 语法错误
// ✅ 使用 TypeScript 解析器
{
"parser": "@typescript-eslint/parser"
}
interface User {
name: string;
} // ✅ 正确解析1.7 parserOptions #
作用:配置解析器选项。
{
"parserOptions": {
"ecmaVersion": 2021, // ECMAScript 版本
"sourceType": "module", // 模块类型
"ecmaFeatures": {
"jsx": true, // 启用 JSX
"globalReturn": false, // 允许全局 return
"impliedStrict": true // 启用严格模式
}
}
}详细说明:
{
"parserOptions": {
// ECMAScript 版本
"ecmaVersion": 2021, // 3, 5, 6/2015, 7/2016, ..., 2021, "latest"
// 模块类型
"sourceType": "module", // "script" 或 "module"
// ECMAScript 特性
"ecmaFeatures": {
"jsx": true, // 启用 JSX
"globalReturn": false, // 允许全局 return
"impliedStrict": false // 启用严格模式
},
// TypeScript 特定(需要 @typescript-eslint/parser)
"project": "./tsconfig.json", // TypeScript 配置文件
"tsconfigRootDir": __dirname // tsconfig.json 所在目录
}
}影响对比:
// sourceType: "script"(默认)
import { foo } from './foo'; // ❌ 错误:不支持 import
// sourceType: "module"
import { foo } from './foo'; // ✅ 正确
// ecmaFeatures.jsx: false
const element = <div>Hello</div>; // ❌ 语法错误
// ecmaFeatures.jsx: true
const element = <div>Hello</div>; // ✅ 正确解析1.8 rules #
作用:配置具体的检查规则。
{
"rules": {
"semi": ["error", "always"], // 要求分号
"quotes": ["error", "single"], // 使用单引号
"no-console": "warn", // 警告 console
"no-unused-vars": "error", // 错误:未使用的变量
"prefer-const": "error", // 优先使用 const
"@typescript-eslint/no-explicit-any": "off" // 关闭规则
}
}规则级别:
{
"rules": {
// 字符串形式
"semi": "off", // 关闭规则
"semi": "warn", // 警告
"semi": "error", // 错误
// 数字形式(不推荐)
"semi": 0, // 关闭
"semi": 1, // 警告
"semi": 2, // 错误
// 数组形式(带配置)
"semi": ["error", "always"], // 错误级别 + 配置
"quotes": ["error", "single", { "avoidEscape": true }]
}
}影响对比:
// semi: "off"
const name = "John" // ✅ 不报错
// semi: "warn"
const name = "John" // ⚠️ 警告:Missing semicolon
// semi: "error"
const name = "John" // ❌ 错误:Missing semicolon
// semi: ["error", "always"]
const name = "John" // ❌ 错误
const name = "John"; // ✅ 正确
// semi: ["error", "never"]
const name = "John"; // ❌ 错误
const name = "John" // ✅ 正确1.9 overrides #
作用:为特定文件应用不同的配置。
{
"rules": {
"no-console": "error"
},
"overrides": [
{
"files": ["*.test.js", "*.spec.js"],
"env": {
"jest": true
},
"rules": {
"no-console": "off" // 测试文件允许 console
}
},
{
"files": ["*.ts", "*.tsx"],
"parser": "@typescript-eslint/parser",
"rules": {
"@typescript-eslint/no-unused-vars": "error"
}
}
]
}使用场景:
{
"overrides": [
// Vue 文件
{
"files": ["*.vue"],
"parser": "vue-eslint-parser"
},
// 配置文件
{
"files": ["*.config.js", ".*rc.js"],
"env": {
"node": true
},
"rules": {
"no-console": "off"
}
},
// TypeScript 文件
{
"files": ["*.ts", "*.tsx"],
"extends": ["plugin:@typescript-eslint/recommended"],
"rules": {
"no-undef": "off" // TS 已经检查
}
}
]
}二、常用规则详解 #
2.1 代码质量规则 #
no-unused-vars #
作用:禁止未使用的变量。
{
"rules": {
"no-unused-vars": ["error", {
"vars": "all", // 检查所有变量
"args": "after-used", // 检查使用后的参数
"ignoreRestSiblings": true // 忽略剩余参数
}]
}
}影响对比:
// ❌ 错误
const unused = 10; // ❌ 'unused' is assigned a value but never used
function calculate(a, b, c) { // ❌ 'c' is defined but never used
return a + b;
}
// ✅ 正确
const used = 10;
console.log(used);
function calculate(a, b) { // 只声明使用的参数
return a + b;
}
// 使用下划线前缀表示故意不使用
function calculate(a, b, _c) { // ✅ 正确
return a + b;
}no-undef #
作用:禁止使用未声明的变量。
{
"rules": {
"no-undef": "error"
}
}影响对比:
// ❌ 错误
console.log(undeclaredVar); // ❌ 'undeclaredVar' is not defined
// ✅ 正确
const declaredVar = 10;
console.log(declaredVar);
// 或在 globals 中声明
{
"globals": {
"myGlobal": "readonly"
}
}
console.log(myGlobal); // ✅ 正确no-const-assign #
作用:禁止修改 const 声明的变量。
{
"rules": {
"no-const-assign": "error"
}
}影响对比:
// ❌ 错误
const PI = 3.14;
PI = 3.14159; // ❌ 'PI' is constant
// ✅ 正确
let value = 10;
value = 20; // ✅ 可以修改 let2.2 最佳实践规则 #
prefer-const #
作用:优先使用 const。
{
"rules": {
"prefer-const": ["error", {
"destructuring": "all", // 解构赋值全用 const
"ignoreReadBeforeAssign": false
}]
}
}影响对比:
// ❌ 错误
let name = "John"; // ❌ 'name' is never reassigned
console.log(name);
// ✅ 正确
const name = "John"; // ✅ 使用 const
console.log(name);
let count = 0; // ✅ 需要修改,使用 let
count++;eqeqeq #
作用:要求使用 === 和 !==。
{
"rules": {
"eqeqeq": ["error", "always"]
}
}影响对比:
// ❌ 错误
if (x == 10) {} // ❌ Expected '===' and instead saw '=='
if (x != null) {} // ❌ Expected '!==' and instead saw '!='
// ✅ 正确
if (x === 10) {} // ✅
if (x !== null) {} // ✅
// 特殊情况:允许与 null 比较
{
"rules": {
"eqeqeq": ["error", "always", { "null": "ignore" }]
}
}
if (x == null) {} // ✅ 允许 x == null 检查 null 和 undefinedno-var #
作用:禁止使用 var。
{
"rules": {
"no-var": "error"
}
}影响对比:
// ❌ 错误
var name = "John"; // ❌ Unexpected var, use let or const instead
// ✅ 正确
const name = "John"; // ✅
let count = 0; // ✅2.3 代码风格规则 #
semi #
作用:要求或禁止分号。
{
"rules": {
"semi": ["error", "always"] // 或 "never"
}
}影响对比:
// semi: ["error", "always"]
const name = "John" // ❌ Missing semicolon
const name = "John"; // ✅
// semi: ["error", "never"]
const name = "John"; // ❌ Extra semicolon
const name = "John" // ✅quotes #
作用:强制使用一致的引号。
{
"rules": {
"quotes": ["error", "single", {
"avoidEscape": true, // 避免转义
"allowTemplateLiterals": true // 允许模板字符串
}]
}
}影响对比:
// quotes: ["error", "single"]
const name = "John"; // ❌ Strings must use singlequote
const name = 'John'; // ✅
// avoidEscape: true
const text = 'It\'s ok'; // ❌ 需要转义
const text = "It's ok"; // ✅ 避免转义,允许双引号
const text = `It's ok`; // ✅ 模板字符串
// allowTemplateLiterals: true
const name = `John`; // ✅ 允许模板字符串
const greeting = `Hello ${name}`; // ✅indent #
作用:强制使用一致的缩进。
{
"rules": {
"indent": ["error", 2, {
"SwitchCase": 1, // switch case 缩进
"VariableDeclarator": 1 // 变量声明缩进
}]
}
}影响对比:
// indent: ["error", 2]
function greet() {
console.log('Hello'); // ❌ Expected indentation of 2 spaces but found 4
}
function greet() {
console.log('Hello'); // ✅
}
// SwitchCase: 1
switch (x) {
case 1: // ❌ Expected indentation of 2 spaces
break;
}
switch (x) {
case 1: // ✅
break;
}2.4 Vue 特定规则 #
vue/multi-word-component-names #
作用:要求组件名为多个单词。
{
"rules": {
"vue/multi-word-component-names": ["error", {
"ignores": ["index", "App"]
}]
}
}影响对比:
<!-- ❌ 错误 -->
<script>
export default {
name: 'Button' // ❌ Component name should be multi-word
}
</script>
<!-- ✅ 正确 -->
<script>
export default {
name: 'BaseButton' // ✅ 多个单词
}
</script>
<!-- 特殊情况 -->
<script>
export default {
name: 'App' // ✅ 在 ignores 中
}
</script>vue/html-indent #
作用:Vue 模板缩进。
{
"rules": {
"vue/html-indent": ["error", 2, {
"attribute": 1,
"baseIndent": 1
}]
}
}2.5 TypeScript 特定规则 #
@typescript-eslint/no-explicit-any #
作用:禁止使用 any 类型。
{
"rules": {
"@typescript-eslint/no-explicit-any": "error"
}
}影响对比:
// ❌ 错误
function process(data: any) { // ❌ Unexpected any
return data;
}
// ✅ 正确
function process(data: unknown) { // ✅ 使用 unknown
return data;
}
function process<T>(data: T): T { // ✅ 使用泛型
return data;
}@typescript-eslint/no-unused-vars #
作用:TypeScript 版本的未使用变量检查。
{
"rules": {
"no-unused-vars": "off", // 关闭基础规则
"@typescript-eslint/no-unused-vars": ["error", {
"argsIgnorePattern": "^_" // 忽略 _ 开头的参数
}]
}
}三、完整推荐配置 #
3.1 纯 JavaScript 项目 #
// .eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'eslint:recommended'
],
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module'
},
rules: {
// 代码质量
'no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
// 最佳实践
'prefer-const': 'error',
'no-var': 'error',
'eqeqeq': ['error', 'always', { null: 'ignore' }],
// 代码风格
'semi': ['error', 'always'],
'quotes': ['error', 'single', { avoidEscape: true }],
'indent': ['error', 2, { SwitchCase: 1 }],
'comma-dangle': ['error', 'never']
}
};3.2 Vue 3 + TypeScript 项目 #
// .eslintrc.cjs
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended' // 必须放在最后
],
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 2021,
parser: '@typescript-eslint/parser',
sourceType: 'module',
project: './tsconfig.json',
extraFileExtensions: ['.vue']
},
plugins: [
'vue',
'@typescript-eslint'
],
rules: {
// Vue 规则
'vue/multi-word-component-names': ['error', {
ignores: ['index', 'App', '[id]']
}],
'vue/component-name-in-template-casing': ['error', 'PascalCase'],
'vue/component-definition-name-casing': ['error', 'PascalCase'],
'vue/html-self-closing': ['error', {
html: {
void: 'always',
normal: 'never',
component: 'always'
}
}],
// TypeScript 规则
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_',
varsIgnorePattern: '^_'
}],
'@typescript-eslint/no-explicit-any': 'warn',
'@typescript-eslint/explicit-module-boundary-types': 'off',
// 通用规则
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off'
},
overrides: [
// 配置文件
{
files: ['*.config.js', '*.config.ts'],
rules: {
'no-console': 'off'
}
}
]
};3.3 React + TypeScript 项目 #
// .eslintrc.js
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
node: true
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module',
ecmaFeatures: {
jsx: true
},
project: './tsconfig.json'
},
plugins: [
'react',
'react-hooks',
'@typescript-eslint'
],
settings: {
react: {
version: 'detect' // 自动检测 React 版本
}
},
rules: {
// React 规则
'react/react-in-jsx-scope': 'off', // React 17+ 不需要
'react/prop-types': 'off', // 使用 TypeScript
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
// TypeScript 规则
'@typescript-eslint/no-unused-vars': ['error', {
argsIgnorePattern: '^_'
}],
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/no-explicit-any': 'warn',
// 通用规则
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off'
}
};3.4 Node.js 项目 #
// .eslintrc.js
module.exports = {
root: true,
env: {
node: true,
es2021: true
},
extends: [
'eslint:recommended'
],
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module'
},
rules: {
// Node.js 特定
'no-console': 'off', // Node.js 允许 console
'no-process-exit': 'error',
// 代码质量
'no-unused-vars': ['error', {
argsIgnorePattern: '^_'
}],
'prefer-const': 'error',
'no-var': 'error'
}
};四、与 Prettier 集成 #
4.1 安装依赖 #
npm install --save-dev eslint prettier eslint-config-prettier eslint-plugin-prettier4.2 配置 ESLint #
// .eslintrc.js
module.exports = {
extends: [
'eslint:recommended',
'plugin:prettier/recommended' // 必须放在最后
]
};4.3 配置 Prettier #
// .prettierrc.json
{
"semi": true,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "es5",
"arrowParens": "always"
}4.4 package.json 脚本 #
{
"scripts": {
"lint": "eslint . --ext .js,.jsx,.ts,.tsx,.vue",
"lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx,.vue --fix",
"format": "prettier --write ."
}
}五、忽略文件 #
5.1 .eslintignore #
# 依赖
node_modules
pnpm-lock.yaml
package-lock.json
# 构建产物
dist
build
.next
.nuxt
out
coverage
# 缓存
.cache
*.log
# 自动生成的文件
*.min.js
auto-imports.d.ts
components.d.ts
# 配置文件
.env
.env.*5.2 在配置文件中忽略 #
module.exports = {
ignorePatterns: [
'dist',
'node_modules',
'*.min.js'
]
};六、常见问题和最佳实践 #
6.1 ESLint vs Prettier #
区别:
| 工具 | 职责 | 示例 |
|---|---|---|
| ESLint | 代码质量 + 部分风格 | 未使用变量、潜在 bug、部分格式 |
| Prettier | 代码格式化 | 缩进、引号、分号、换行 |
推荐做法:
- 使用 ESLint 检查代码质量
- 使用 Prettier 格式化代码
- 使用
eslint-config-prettier禁用 ESLint 中与 Prettier 冲突的规则
module.exports = {
extends: [
'eslint:recommended',
'plugin:prettier/recommended' // 禁用冲突规则并启用 Prettier 规则
]
};6.2 性能优化 #
1. 使用缓存:
{
"scripts": {
"lint": "eslint . --cache --cache-location node_modules/.cache/eslint"
}
}2. 限制检查文件:
{
"scripts": {
"lint": "eslint src --ext .js,.jsx,.ts,.tsx"
}
}3. 使用 ignorePatterns:
module.exports = {
ignorePatterns: ['dist', 'node_modules', '*.min.js']
};6.3 VS Code 集成 #
.vscode/settings.json:
{
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact",
"vue"
],
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}6.4 Git Hooks 集成 #
使用 husky + lint-staged:
npm install --save-dev husky lint-staged
npx husky initpackage.json:
{
"lint-staged": {
"*.{js,jsx,ts,tsx,vue}": [
"eslint --fix",
"prettier --write"
]
}
}.husky/pre-commit:
#!/usr/bin/env sh
npx lint-staged6.5 CI 中运行 #
.github/workflows/lint.yml:
name: Lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: npm ci
- run: npm run lint6.6 迁移现有项目 #
步骤:
# 1. 安装 ESLint
npm install --save-dev eslint
# 2. 初始化配置
npx eslint --init
# 3. 检查问题
npm run lint
# 4. 自动修复
npm run lint:fix
# 5. 手动修复剩余问题
# 6. 提交更改
git add .
git commit -m "chore: 添加 ESLint 配置"6.7 禁用规则的正确方式 #
文件级别:
/* eslint-disable */
// 整个文件禁用
/* eslint-enable */
// 重新启用行级别:
// eslint-disable-next-line
const unused = 10;
const unused = 10; // eslint-disable-line
// 禁用特定规则
// eslint-disable-next-line no-console
console.log('Debug');块级别:
/* eslint-disable no-console */
console.log('Debug 1');
console.log('Debug 2');
/* eslint-enable no-console */6.8 常见错误解决 #
1. Parsing error: Cannot find module '@typescript-eslint/parser'
npm install --save-dev @typescript-eslint/parser @typescript-eslint/eslint-plugin2. 'module' is not defined
// .eslintrc.js
module.exports = {
env: {
node: true // 添加 node 环境
}
};3. ESLint 和 Prettier 冲突
npm install --save-dev eslint-config-prettiermodule.exports = {
extends: [
'eslint:recommended',
'plugin:prettier/recommended' // 必须放在最后
]
};七、总结 #
必须配置的选项 #
- root:
true- 限制配置查找 - env - 声明运行环境
- extends - 继承推荐配置
- parser - TypeScript/Vue 项目必需
- rules - 根据团队规范自定义
推荐工作流 #
- 使用
eslint:recommended作为基础 - 根据框架添加对应插件(Vue/React/TypeScript)
- 集成 Prettier 处理代码格式
- 配置 Git Hooks 自动检查
- 在 CI 中运行 lint
常用命令 #
# 检查代码
npx eslint .
# 自动修复
npx eslint . --fix
# 检查特定文件
npx eslint src/index.js
# 使用缓存
npx eslint . --cache
# 输出 JSON 格式
npx eslint . --format json
# 检查并报告未使用的禁用指令
npx eslint . --report-unused-disable-directives学习建议 #
- 从
eslint:recommended开始 - 逐步添加规则,不要一次性开启所有
- 理解每个规则的作用,而不是盲目配置
- 使用
--fix自动修复可修复的问题 - 定期更新 ESLint 和插件版本