ESLint + Prettier:代码风格统一神器,让团队不再为分号吵架

手把手教你配置 ESLint 和 Prettier,从此告别代码风格争论,让工具替你做决定。

12 分钟阅读
小明

代码风格之战:一场没有赢家的争论

"用 Tab 还是空格?"

"分号要不要加?"

"花括号换行还是不换行?"

如果你在团队里工作过,一定经历过这样的讨论。而且你会发现,这些讨论往往比技术架构的讨论还激烈——因为每个人都有自己的"舒适区"。

我曾经见过两个同事为了"对象最后一个属性要不要加逗号"这个问题,在群里吵了整整一下午。最后的结论是什么呢?没有结论,各写各的。

结果就是:代码库里风格混乱,有的文件用 Tab,有的用空格;有的加分号,有的不加。每次 Code Review 的时候,50% 的讨论都在纠结格式问题,真正的逻辑问题反而被忽略了。

今天,我们要用 ESLint + Prettier 彻底终结这场战争。

先搞清楚:ESLint 和 Prettier 各管啥?

很多人把这两个工具搞混,觉得它们是干同一件事的。其实不然:

ESLint:代码质量警察

ESLint 主要关注的是代码质量潜在错误

// ESLint 会警告你这些问题

// 1. 使用了未声明的变量
console.log(userName);  // 'userName' is not defined

// 2. 声明了但没使用的变量
const unused = 'hello';  // 'unused' is defined but never used

// 3. 可能的逻辑错误
if (x = 1) {  // Expected '===' and instead saw '='
  console.log('oops');
}

// 4. 不推荐的写法
with (obj) {  // Unexpected use of 'with' statement
  console.log(name);
}

Prettier:代码格式美容师

Prettier 只关注代码格式,它不管你的代码逻辑对不对,只管让代码"好看":

// Prettier 处理前
const user={name:'小明',age:25,skills:['JavaScript','TypeScript','Vue','React']}

// Prettier 处理后
const user = {
  name: "小明",
  age: 25,
  skills: ["JavaScript", "TypeScript", "Vue", "React"],
};

一句话总结

  • ESLint:检查代码写得对不对
  • Prettier:检查代码写得美不美

这两个工具配合使用,才是完整的代码规范解决方案。

从零开始配置:手把手教程

第一步:安装依赖

# 创建一个新项目(如果你已有项目,跳过这步)
mkdir my-project && cd my-project
npm init -y

# 安装 ESLint
npm install eslint --save-dev

# 安装 Prettier
npm install prettier --save-dev

# 安装 ESLint 和 Prettier 的配合插件(重要!)
npm install eslint-config-prettier eslint-plugin-prettier --save-dev

这里要解释一下最后安装的两个包:

  • eslint-config-prettier:关闭 ESLint 中与 Prettier 冲突的规则
  • eslint-plugin-prettier:让 ESLint 能够运行 Prettier 检查

第二步:配置 ESLint

创建 .eslintrc.js 文件:

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:prettier/recommended',  // 这行放在最后!
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  rules: {
    // 在这里添加你的自定义规则
    'no-console': 'warn',
    'no-unused-vars': 'warn',
    'prefer-const': 'error',
  },
};

重点plugin:prettier/recommended 一定要放在 extends 数组的最后,因为它会覆盖前面的格式相关规则。

第三步:配置 Prettier

创建 .prettierrc 文件:

{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "es5",
  "printWidth": 80,
  "bracketSpacing": true,
  "arrowParens": "avoid"
}

让我来解释每个配置的含义:

配置含义示例
semi: true语句末尾加分号const a = 1;
singleQuote: true使用单引号'hello'
tabWidth: 2缩进用 2 个空格··if (true)
trailingComma: "es5"对象/数组末尾加逗号{ a: 1, b: 2, }
printWidth: 80每行最多 80 字符自动换行
bracketSpacing: true对象括号内加空格{ a: 1 }
arrowParens: "avoid"箭头函数单参数不加括号x => x * 2

第四步:添加忽略文件

创建 .eslintignore

node_modules
dist
build
*.min.js

创建 .prettierignore

node_modules
dist
build
pnpm-lock.yaml
package-lock.json

第五步:添加 npm scripts

package.json 中添加:

{
  "scripts": {
    "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
    "lint:fix": "eslint . --ext .js,.jsx,.ts,.tsx --fix",
    "format": "prettier --write .",
    "format:check": "prettier --check ."
  }
}

进阶配置:TypeScript 项目

如果你的项目使用 TypeScript,需要额外安装一些依赖:

npm install @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev

然后修改 .eslintrc.js

module.exports = {
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
  ],
  rules: {
    // TypeScript 相关规则
    '@typescript-eslint/no-unused-vars': 'warn',
    '@typescript-eslint/explicit-function-return-type': 'off',
    '@typescript-eslint/no-explicit-any': 'warn',
  },
};

进阶配置:Vue 项目

Vue 项目需要额外的解析器:

npm install eslint-plugin-vue --save-dev

.eslintrc.js 配置:

module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-recommended',  // Vue 3 项目
    // 'plugin:vue/recommended',    // Vue 2 项目
    'plugin:prettier/recommended',
  ],
  rules: {
    'vue/multi-word-component-names': 'off',
    'vue/no-v-html': 'warn',
  },
};

编辑器集成:保存时自动格式化

配置文件写好了,但每次都要手动运行命令太麻烦。让我们配置编辑器自动格式化。

VS Code 配置

安装插件:

  • ESLint
  • Prettier - Code formatter

创建 .vscode/settings.json

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

现在,每次保存文件时:

  1. Prettier 会自动格式化代码
  2. ESLint 会自动修复可以修复的问题

爽翻了!

Git Hooks:提交前自动检查

编辑器配置好了,但万一有人不用 VS Code 呢?万一有人忘记保存就提交了呢?

我们需要一道最后的防线:Git Hooks

安装 Husky 和 lint-staged

npm install husky lint-staged --save-dev

# 初始化 Husky
npx husky install

# 添加 pre-commit hook
npx husky add .husky/pre-commit "npx lint-staged"

配置 lint-staged

package.json 中添加:

{
  "lint-staged": {
    "*.{js,jsx,ts,tsx,vue}": [
      "eslint --fix",
      "prettier --write"
    ],
    "*.{json,md,css,scss}": [
      "prettier --write"
    ]
  }
}

现在,每次 git commit 之前,都会自动对暂存的文件进行:

  1. ESLint 检查和修复
  2. Prettier 格式化

如果有错误无法自动修复,提交会被阻止。再也不用担心格式问题流入代码库了!

常见问题排查

问题 1:ESLint 和 Prettier 规则冲突

症状:保存时代码反复跳动,或者 ESLint 报错 Prettier 刚改的格式。

解决:确保 eslint-config-prettier 在 extends 数组的最后位置。

extends: [
  'eslint:recommended',
  'plugin:prettier/recommended',  // 必须在最后
],

问题 2:.vue 文件格式化不生效

症状:JS/TS 文件正常,但 Vue 文件不格式化。

解决:在 .vscode/settings.json 中明确指定:

{
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  }
}

问题 3:某个规则太烦人想关闭

症状:某个 ESLint 规则频繁报错,但你觉得没必要。

解决:在 .eslintrc.js 的 rules 中关闭:

rules: {
  'no-console': 'off',           // 关闭规则
  'no-unused-vars': 'warn',      // 改为警告
}

问题 4:想在某个文件临时禁用规则

解决:使用注释禁用:

/* eslint-disable no-console */
console.log('这里不会报警告');
/* eslint-enable no-console */

// 或者只禁用一行
console.log('just this line'); // eslint-disable-line no-console

我的推荐配置

分享一下我团队目前使用的配置,可以直接拿去用:

.prettierrc

{
  "semi": false,
  "singleQuote": true,
  "tabWidth": 2,
  "trailingComma": "all",
  "printWidth": 100,
  "bracketSpacing": true,
  "arrowParens": "avoid",
  "endOfLine": "lf",
  "vueIndentScriptAndStyle": true
}

是的,我们选择了不加分号。理由是:

  1. 现代 JavaScript 的自动分号插入(ASI)已经很完善
  2. 少打一个字符,代码更简洁
  3. TypeScript/Prettier 会帮你处理边界情况

.eslintrc.js

module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:vue/vue3-recommended',
    'plugin:prettier/recommended',
  ],
  parser: 'vue-eslint-parser',
  parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  rules: {
    // 允许 console,但生产环境打包时应该移除
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
    
    // TypeScript
    '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
    '@typescript-eslint/no-explicit-any': 'warn',
    
    // Vue
    'vue/multi-word-component-names': 'off',
    'vue/no-v-html': 'off',
  },
}

写在最后

配置 ESLint + Prettier 可能会花你一两个小时,但它带来的收益是巨大的:

  1. 团队不再为代码风格争论——工具说了算
  2. Code Review 更高效——专注于逻辑,而非格式
  3. 代码库保持一致——无论谁写的代码,看起来都一样
  4. 减少低级错误——ESLint 帮你提前发现问题

记住一句话:好的工具应该让人感觉不到它的存在。配置完成后,你只需要专注于写代码,格式化的事情就交给工具吧。

下一篇,我们来聊聊 async/await 的错误处理——这可是面试必考题哦。