代码质量保障:ESLint + Prettier + Stylelint 三剑客完美配置

本文是《从零到一:构建现代化企业级 Monorepo 项目实战》系列的第四篇。前面我们完成了项目搭建,这篇文章将配置完整的代码质量工具链,让团队协作更高效。

🎯 本文目标

读完这篇文章,你将学会:

  • ESLint 9.x 扁平配置的最佳实践
  • Prettier 与 ESLint 的冲突解决
  • Stylelint 样式检查配置
  • Git Hooks 自动化检查
  • VSCode 编辑器集成

📖 为什么需要代码质量工具?

真实场景

没有工具时的团队协作:

typescript 复制代码
// 开发者 A 的代码
function getUserInfo() {
  const data = { name: '张三', age: 25 }
  return data
}

// 开发者 B 的代码
function getUserInfo() {
  const data = {
    name: '李四',
    age: 30,
  }
  return data
}

// 同一个团队,两种完全不同的代码风格!😱

配置工具后:

typescript 复制代码
// 所有人的代码风格统一
function getUserInfo() {
  const data = {
    name: '张三',
    age: 25,
  }
  return data
}

// ✅ 统一、规范、易读

🔧 工具链架构

bash 复制代码
代码质量工具链
├── ESLint          # JS/TS 代码检查
├── Prettier        # 代码格式化
├── Stylelint       # CSS/SCSS 检查
├── Husky           # Git Hooks
└── lint-staged     # 提交时增量检查

1️⃣ ESLint 9.x 扁平配置

为什么是 ESLint 9.x?

旧版配置(.eslintrc.js):

javascript 复制代码
// ❌ 已废弃
module.exports = {
  extends: ['eslint:recommended', 'plugin:vue/vue3-recommended'],
  rules: {
    'no-console': 'warn',
  },
}

新版配置(eslint.config.js):

javascript 复制代码
// ✅ ESLint 9.x 扁平配置
import js from '@eslint/js'
import vue from 'eslint-plugin-vue'

export default [
  js.configs.recommended,
  ...vue.configs['flat/recommended'],
  {
    rules: {
      'no-console': 'warn',
    },
  },
]

优势:

  • ✅ 更简单的配置结构
  • ✅ 更好的 TypeScript 支持
  • ✅ 更灵活的规则组合

安装依赖

bash 复制代码
# 安装 ESLint 及相关插件
pnpm add -Dw eslint \
  @eslint/js \
  @typescript-eslint/eslint-plugin \
  @typescript-eslint/parser \
  eslint-plugin-vue \
  vue-eslint-parser \
  eslint-config-prettier \
  eslint-plugin-prettier

完整配置文件

javascript 复制代码
// eslint.config.js
import js from '@eslint/js'
import tseslint from '@typescript-eslint/eslint-plugin'
import tsparser from '@typescript-eslint/parser'
import prettierConfig from 'eslint-config-prettier'
import vue from 'eslint-plugin-vue'
import vueParser from 'vue-eslint-parser'

export default [
  // 基础 JavaScript 配置
  js.configs.recommended,

  // Vue 3 配置
  ...vue.configs['flat/recommended'],

  // 全局配置
  {
    files: ['**/*.{js,ts,tsx,vue}'],
    languageOptions: {
      ecmaVersion: 'latest',
      sourceType: 'module',
      globals: {
        process: 'readonly',
        console: 'readonly',
        window: 'readonly',
        document: 'readonly',
      },
    },
    rules: {
      'no-console': 'off',
      'no-debugger': 'error',
      'prefer-const': 'error',
      'no-var': 'error',
    },
  },

  // TypeScript 配置
  {
    files: ['**/*.{ts,tsx}'],
    languageOptions: {
      parser: tsparser,
    },
    plugins: {
      '@typescript-eslint': tseslint,
    },
    rules: {
      '@typescript-eslint/no-unused-vars': 'error',
      '@typescript-eslint/no-explicit-any': 'off',
    },
  },

  // Vue 文件配置
  {
    files: ['**/*.vue'],
    languageOptions: {
      parser: vueParser,
      parserOptions: {
        parser: tsparser,
        extraFileExtensions: ['.vue'],
      },
    },
    rules: {
      'vue/multi-word-component-names': 'off',
      'vue/no-v-html': 'off',
    },
  },

  // 忽略文件
  {
    ignores: ['node_modules/**', '**/dist/**', '**/.turbo/**', 'coverage/**'],
  },

  // Prettier 配置(必须放最后)
  prettierConfig,
]

在 package.json 中添加脚本

json 复制代码
{
  "scripts": {
    "lint": "turbo run lint",
    "lint:fix": "turbo run lint:fix"
  }
}

各包的 lint 脚本

json 复制代码
// packages/shared/package.json
{
  "scripts": {
    "lint": "eslint . --ext .js,.ts",
    "lint:fix": "eslint . --ext .js,.ts --fix"
  }
}

// packages/ui/package.json
{
  "scripts": {
    "lint": "eslint . --ext .js,.ts,.vue",
    "lint:fix": "eslint . --ext .js,.ts,.vue --fix"
  }
}

2️⃣ Prettier 代码格式化

安装和配置

bash 复制代码
# 安装 Prettier
pnpm add -Dw prettier

创建 .prettierrc

json 复制代码
{
  "semi": false,
  "singleQuote": true,
  "printWidth": 120,
  "tabWidth": 2,
  "trailingComma": "es5",
  "arrowParens": "avoid",
  "endOfLine": "lf"
}

创建 .prettierignore

csharp 复制代码
node_modules
dist
.turbo
coverage
pnpm-lock.yaml
CHANGELOG.md

添加脚本

json 复制代码
{
  "scripts": {
    "format": "turbo run format",
    "format:check": "turbo run format:check"
  }
}
json 复制代码
// packages/*/package.json
{
  "scripts": {
    "format": "prettier --write \"src/**/*.{js,ts,vue,json}\"",
    "format:check": "prettier --check \"src/**/*.{js,ts,vue,json}\""
  }
}

ESLint 与 Prettier 冲突解决

关键配置:

javascript 复制代码
// eslint.config.js
import prettierConfig from 'eslint-config-prettier'

export default [
  // ... 其他配置

  prettierConfig, // 必须放在最后,关闭冲突规则

  // 重新启用某些规则(让 ESLint 能检测到错误)
  {
    rules: {
      semi: ['error', 'never'],
      quotes: ['error', 'single'],
    },
  },
]

工作流程:

复制代码
编写代码 → ESLint 检查语法 → Prettier 格式化 → 完美代码 ✅

3️⃣ Stylelint 样式检查

安装依赖

bash 复制代码
pnpm add -Dw stylelint \
  stylelint-config-standard \
  stylelint-config-standard-scss \
  stylelint-config-recommended-vue \
  postcss-html \
  postcss-scss

配置文件

json 复制代码
// .stylelintrc.json
{
  "extends": ["stylelint-config-standard", "stylelint-config-standard-scss", "stylelint-config-recommended-vue"],
  "rules": {
    "selector-class-pattern": null,
    "custom-property-pattern": null,
    "scss/dollar-variable-pattern": null,
    "selector-pseudo-class-no-unknown": [
      true,
      {
        "ignorePseudoClasses": ["deep", "global"]
      }
    ]
  },
  "ignoreFiles": ["node_modules/**", "dist/**", ".turbo/**", "coverage/**"]
}

添加脚本

json 复制代码
// 根 package.json
{
  "scripts": {
    "lint:style": "turbo run lint:style",
    "lint:style:fix": "turbo run lint:style:fix"
  }
}

// packages/ui/package.json
{
  "scripts": {
    "lint:style": "stylelint \"src/**/*.{css,scss,vue}\"",
    "lint:style:fix": "stylelint \"src/**/*.{css,scss,vue}\" --fix"
  }
}

4️⃣ Git Hooks 自动化

安装 Husky

bash 复制代码
pnpm add -Dw husky lint-staged
pnpm exec husky init

配置 pre-commit

bash 复制代码
# .husky/pre-commit
pnpm lint-staged

配置 lint-staged

json 复制代码
// .lintstagedrc.json
{
  "*.{js,ts,tsx,vue}": ["eslint --fix", "prettier --write"],
  "*.{css,scss,vue}": ["stylelint --fix"],
  "*.{json,md}": ["prettier --write"]
}

配置 commit-msg

bash 复制代码
# 安装 commitlint
pnpm add -Dw @commitlint/cli @commitlint/config-conventional

# .husky/commit-msg
npx --no -- commitlint --edit $1
javascript 复制代码
// commitlint.config.js
export default {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat', // 新功能
        'fix', // Bug 修复
        'docs', // 文档
        'style', // 格式
        'refactor', // 重构
        'perf', // 性能
        'test', // 测试
        'chore', // 构建/工具
      ],
    ],
  },
}

5️⃣ VSCode 集成

安装推荐扩展

创建 .vscode/extensions.json

json 复制代码
{
  "recommendations": ["dbaeumer.vscode-eslint", "esbenp.prettier-vscode", "stylelint.vscode-stylelint", "vue.volar"]
}

配置 VSCode 设置

创建 .vscode/settings.json

json 复制代码
{
  // ESLint 配置
  "eslint.enable": true,
  "eslint.run": "onType",
  "eslint.format.enable": true,

  // Prettier 配置
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,

  // Stylelint 配置
  "stylelint.enable": true,
  "stylelint.validate": ["css", "scss", "vue"],

  // Vue 配置
  "volar.takeOverMode": true,

  // 保存时自动修复
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "never" // 关闭自动修复,只显示错误
  },

  // 文件关联
  "files.associations": {
    "*.css": "css",
    "*.scss": "scss"
  }
}

EditorConfig 统一编辑器配置

ini 复制代码
# .editorconfig
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

🎯 完整的工作流

开发阶段

bash 复制代码
# 1. 编写代码
vim packages/ui/src/components/Button/button.vue

# 2. 保存时自动格式化(Prettier)
# 3. 编辑器实时显示 ESLint 错误(红色波浪线)

提交阶段

bash 复制代码
git add .
git commit -m "feat: 添加 Button 组件"

# 自动触发:
# 1. lint-staged → 检查暂存文件
# 2. ESLint 自动修复
# 3. Prettier 格式化
# 4. Stylelint 修复样式
# 5. commitlint 检查 commit 消息

# 如果有错误,提交会被阻止

CI/CD 阶段

yaml 复制代码
# .gitlab-ci.yml
lint:
  stage: check
  script:
    - pnpm lint:all
    - pnpm format:check

🚀 实战:配置完整的检查流程

第一步:安装所有依赖

bash 复制代码
# 创建安装脚本
cat > install-tools.sh << 'EOF'
#!/bin/bash

# ESLint
pnpm add -Dw eslint \
  @eslint/js \
  @typescript-eslint/eslint-plugin \
  @typescript-eslint/parser \
  eslint-plugin-vue \
  vue-eslint-parser \
  eslint-config-prettier \
  eslint-plugin-prettier

# Prettier
pnpm add -Dw prettier

# Stylelint
pnpm add -Dw stylelint \
  stylelint-config-standard \
  stylelint-config-standard-scss \
  stylelint-config-recommended-vue \
  postcss-html \
  postcss-scss

# Git Hooks
pnpm add -Dw husky lint-staged

# Commitlint
pnpm add -Dw @commitlint/cli @commitlint/config-conventional

echo "✅ 所有工具安装完成!"
EOF

chmod +x install-tools.sh
./install-tools.sh

第二步:创建配置文件

bash 复制代码
# ESLint
touch eslint.config.js

# Prettier
touch .prettierrc .prettierignore

# Stylelint
touch .stylelintrc.json

# Commitlint
touch commitlint.config.js

# lint-staged
touch .lintstagedrc.json

# EditorConfig
touch .editorconfig

第三步:配置 Turbo 任务

json 复制代码
// turbo.json
{
  "tasks": {
    "lint": {
      "dependsOn": [],
      "inputs": ["$TURBO_DEFAULT$", "!{dist,.turbo}/**"],
      "cache": true
    },
    "lint:fix": {
      "dependsOn": [],
      "cache": false,
      "outputs": []
    },
    "lint:style": {
      "cache": true
    },
    "lint:style:fix": {
      "cache": false
    },
    "format": {
      "cache": false
    },
    "format:check": {
      "cache": true
    }
  }
}

第四步:添加统一脚本

json 复制代码
// 根 package.json
{
  "scripts": {
    "lint": "turbo run lint",
    "lint:fix": "turbo run lint:fix",
    "lint:style": "turbo run lint:style",
    "lint:style:fix": "turbo run lint:style:fix",
    "format": "turbo run format",
    "format:check": "turbo run format:check",
    "lint:all": "turbo run lint lint:style",
    "fix:all": "turbo run lint:fix lint:style:fix format"
  }
}

🎨 各工具的职责划分

工具 职责 检查内容 能否自动修复
ESLint 代码质量 语法错误、代码规范、潜在bug ✅ 部分可以
Prettier 代码格式 缩进、换行、引号、分号 ✅ 全部可以
Stylelint 样式质量 CSS/SCSS 规范、顺序 ✅ 部分可以

示例代码

typescript 复制代码
// ❌ 有问题的代码
const data = { name: 'test', value: 123 }
if (data) {
  console.log(data)
}

// ESLint 检查后
const data = { name: 'test', value: 123 } // ✅ 变量声明规范
if (data) {
  // ✅ 条件语句格式
  console.log(data) // ✅ 缩进正确
}

// Prettier 格式化后
const data = { name: 'test', value: 123 }
if (data) {
  console.log(data)
}
// ✅ 完美!

🔥 实战案例:修复代码问题

场景1:多余的空行

typescript 复制代码
// ❌ 错误:过多的空行
function test() {
  console.log('test')

  return true
}

ESLint 规则:

javascript 复制代码
{
  rules: {
    'no-multiple-empty-lines': ['error', {
      max: 1,      // 最多1个空行
      maxEOF: 1,   // 文件末尾最多1个空行
      maxBOF: 0    // 文件开头不允许空行
    }]
  }
}

修复后:

typescript 复制代码
// ✅ 正确
function test() {
  console.log('test')

  return true
}

场景2:未使用的变量

typescript 复制代码
// ❌ 错误
function calculate() {
  const unused = 123 // 未使用
  const result = 456
  return result
}

ESLint 会报错:

vbnet 复制代码
error: 'unused' is assigned a value but never used

修复:

typescript 复制代码
// ✅ 删除未使用的变量
function calculate() {
  const result = 456
  return result
}

场景3:样式属性顺序

scss 复制代码
// ❌ 样式属性乱序
.button {
  cursor: pointer;
  padding: 10px;
  display: flex;
  color: white;
  background: blue;
}

Stylelint 自动修复:

scss 复制代码
// ✅ 按照标准顺序排列
.button {
  display: flex;
  padding: 10px;
  color: white;
  cursor: pointer;
  background: blue;
}

🤖 自动化检查流程

Git Hooks 触发时机

bash 复制代码
# pre-commit: 提交前检查
git commit
→ lint-staged 运行
  → ESLint 检查修改的文件
  → Prettier 格式化修改的文件
  → Stylelint 检查样式文件
→ 如果有错误,终止提交 ❌
→ 如果通过,继续提交 ✅

# commit-msg: 检查提交信息
git commit -m "add button"
→ commitlint 检查格式
→ ❌ 错误:缺少类型前缀

git commit -m "feat: add button"
→ ✅ 通过检查

lint-staged 增量检查

传统方式:

bash 复制代码
# 检查所有文件(慢)
eslint .
# 1000个文件,耗时 30s 😫

lint-staged 方式:

bash 复制代码
# 只检查暂存的文件(快)
# 修改了 3 个文件,耗时 0.5s ⚡

配置:

json 复制代码
{
  "*.{js,ts,vue}": [
    "eslint --fix", // 1. 修复 ESLint 问题
    "prettier --write" // 2. 格式化代码
  ],
  "*.{css,scss,vue}": [
    "stylelint --fix" // 3. 修复样式问题
  ]
}

💡 团队协作最佳实践

1. 统一的代码风格

javascript 复制代码
// ✅ 团队统一使用单引号
const name = 'gdu-common'

// ✅ 团队统一不使用分号
const version = '1.0.0'

// ✅ 团队统一使用 2 空格缩进
function hello() {
  console.log('hello')
}

2. 渐进式规则

第一阶段:基础规则

javascript 复制代码
{
  rules: {
    'no-console': 'off',        // 允许 console
    'no-debugger': 'error',     // 禁止 debugger
    '@typescript-eslint/no-explicit-any': 'off'  // 允许 any
  }
}

第二阶段:严格规则

javascript 复制代码
{
  rules: {
    'no-console': 'warn',       // 警告 console
    '@typescript-eslint/no-explicit-any': 'warn'  // 警告 any
  }
}

第三阶段:最严格

javascript 复制代码
{
  rules: {
    'no-console': 'error',      // 禁止 console
    '@typescript-eslint/no-explicit-any': 'error'  // 禁止 any
  }
}

3. 规则说明文档

markdown 复制代码
# 代码规范

## 命名规范

- 变量:小驼峰 `userInfo`
- 常量:大写下划线 `API_BASE_URL`
- 组件:大驼峰 `ButtonComponent`
- 文件:小写连字符 `user-info.ts`

## 代码风格

- 使用单引号
- 不使用分号
- 2 空格缩进
- 最多 1 个连续空行

## Vue 组件规范

- 使用 Composition API
- Props 必须定义类型
- 事件使用 emit 定义

📊 效果展示

代码质量提升

配置前:

typescript 复制代码
// 各种问题:
;-代码风格不统一 - 存在未使用的变量 - 缺少类型定义 - 样式属性乱序

配置后:

bash 复制代码
# 运行检查
pnpm lint:all

# 输出
✓ @gdu-common/shared:lint (1.2s)
✓ @gdu-common/utils:lint (0.8s)
✓ @gdu-common/ui:lint (2.1s)
✓ @gdu-common/ui:lint:style (1.5s)

# ✅ 0 errors, 0 warnings

提交前自动修复

bash 复制代码
git add .
git commit -m "feat: add button component"

# 输出
✔ Preparing lint-staged...
✔ Running tasks for staged files...
  ✔ packages/ui/src/**/*.{js,ts,vue}
    ✔ eslint --fix
    ✔ prettier --write
  ✔ packages/ui/src/**/*.{css,scss,vue}
    ✔ stylelint --fix
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...

# ✅ 自动修复完成,提交成功

🤔 常见问题

Q1: ESLint 和 Prettier 冲突怎么办?

解决方案:

javascript 复制代码
// 1. 安装 eslint-config-prettier
pnpm add -Dw eslint-config-prettier

// 2. 在 eslint.config.js 最后添加
import prettierConfig from 'eslint-config-prettier'

export default [
  // ... 其他配置
  prettierConfig  // 必须在最后
]

Q2: 如何在编辑器中实时看到错误?

配置 VSCode:

json 复制代码
{
  "eslint.run": "onType", // 输入时检查
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "never" // 不自动修复,只显示错误
  }
}

Q3: 提交时检查太慢怎么办?

使用 lint-staged 增量检查:

json 复制代码
// 只检查修改的文件
{
  "*.ts": "eslint --fix" // 不是 "eslint ."
}

Q4: 如何跳过 Git Hooks?

bash 复制代码
# 不推荐,但紧急情况可以用
git commit --no-verify -m "feat: urgent fix"

🎉 总结

完整的代码质量工具链配置:

工具清单

  • ✅ ESLint 9.x(扁平配置)
  • ✅ Prettier(代码格式化)
  • ✅ Stylelint(样式检查)
  • ✅ Husky(Git Hooks)
  • ✅ lint-staged(增量检查)
  • ✅ Commitlint(提交信息规范)

效果

  • 📈 代码质量显著提升
  • 🚀 自动化程度 100%
  • 👥 团队协作更顺畅
  • ⏱️ Code Review 时间减少 50%

关键配置

bash 复制代码
# 一键检查所有代码
pnpm lint:all

# 一键修复所有问题
pnpm fix:all

# 提交时自动检查和修复
git commit

在下一篇文章中,我将分享版本管理的实践,包括:

  • Changeset 工作流程
  • 语义化版本控制
  • CHANGELOG 自动生成
  • 自动化发布流程

🔗 系列文章


代码质量工具配置好了吗?觉得有用的话点个赞支持一下! 👍

你的团队用的是什么代码检查工具?有什么踩坑经验?欢迎评论区分享! 💬

相关推荐
Mintopia3 小时前
🧭 Next.js 架构与运维:当现代前端拥有了“分布式的灵魂”
前端·javascript·全栈
尘世中一位迷途小书童4 小时前
从零搭建:pnpm + Turborepo 项目架构实战(含完整代码)
前端·架构
JarvanMo4 小时前
Flutter 中的 ClipRRect | 每日 Flutter 组件
前端
某柚啊4 小时前
iOS移动端H5键盘弹出时页面布局异常和滚动解决方案
前端·javascript·css·ios·html5
心.c4 小时前
如何学习Lodash源码?
前端·javascript·学习
JamSlade4 小时前
react 无限画布难点和实现
前端·react.js
im_AMBER4 小时前
React 02
前端·笔记·学习·react.js·前端框架
浩男孩4 小时前
🍀我实现了个摸鱼聊天室🚀
前端
玲小珑4 小时前
LangChain.js 完全开发手册(十六)实战综合项目二:AI 驱动的代码助手
前端·langchain·ai编程