ESLint + Prettier + Husky + lint-staged:建立自动化的高效前端工作流

前言

在团队协作中,代码规范往往是一个容易引发争议却又不得不解决的问题。每个人都有自己的编码习惯,有人喜欢加分号,有人不喜欢;有人用两个空格缩进,有人用四个;有人变量命名用 camelCase,有人用 snake_case。这些差异在 Code Review 时往往演变成无休止的争论,消耗着团队的宝贵时间。

这就是为什么要建立自动化代码规范工作流------让工具做工具擅长的事,让人做人擅长的事。

为什么需要自动化代码规范?

没有规范带来的问题

javascript 复制代码
// 团队成员A写的代码
function fetchData(){
let result = getData()
return result
}

// 团队成员B写的代码
function fetchData() {
  const result = getData();
  return result;
}

上述两段代码看起来差不多,但:

  1. 格式不一致(缩进、空格、分号)
  2. 变量命名风格不同
  3. Code Review 时会争论这些细节

有了自动化工具之后

javascript 复制代码
// 不管我们怎么写,保存时自动变成统一格式
function fetchData() {
  const result = getData()
  return result
}
// 提交时自动检查,有问题就拦截
// 再也不用手动改格式了

自动化工作流的价值

markdown 复制代码
传统流程:
写代码 → 手动检查 → 提交 → Code Review → 发现问题 → 修改 → 再次提交

自动化流程:
写代码 → 保存时自动格式化 → 提交时自动检查 → 提交成功
                        ↓
                    发现问题自动拦截

收益:
- 减少 90% 的代码风格争论
- 提前发现 70% 的潜在错误
- Code Review 时间缩短 50%
- 新人融入时间减少 60%

工具链全景图

四大工具的分工

ESLint:代码质量检查

  • 发现潜在错误(未定义变量、未使用变量)
  • 强制最佳实践(使用 === 代替 ==)
  • 统一代码风格(但能力有限)

Prettier:代码美容师

  • 统一代码风格(空格、换行、引号)
  • 专注格式化,不做质量检查

Husky:看门人

  • 在 Git 操作时触发脚本
  • 确保提交前代码符合规范

lint-staged:高效助手

  • 只检查即将提交的文件
  • 避免检查整个项目,提高效率

工作流程示意图

sql 复制代码
开发阶段
┌─────────────────┐
│  VS Code 编辑器 │
│  - 保存时格式化 │
│  - 实时错误提示 │
└────────┬────────┘
         ↓
Git 提交阶段
┌─────────────────┐
│   git commit    │
└────────┬────────┘
         ↓
Husky 触发 pre-commit
┌─────────────────┐
│  执行 lint-staged│
└────────┬────────┘
         ↓
lint-staged 检查暂存区
┌─────────────────┐
│ 1. 运行 ESLint  │
│ 2. 运行 Prettier│
└────────┬────────┘
    有问题?→ 拦截提交
         ↓
    没问题 → 提交成功

ESLint - 代码质量守门员

什么是 ESLint?

ESLint 就像考试时的阅卷老师,专门帮我们找出代码中的"错误"和"不规范":

javascript 复制代码
// 1. 未使用的变量
let unusedVar = '没人用我'  // ESLint: 'unusedVar' is defined but never used

// 2. 未定义的变量
console.log(notDefined)  // ESLint: 'notDefined' is not defined

// 3. 不安全的比较
if (count == 1) {  // ESLint: Expected '===' and instead saw '=='
  // ...
}

// 4. 重复定义
let name = '张三'
let name = '李四'  // ESLint: 'name' is already defined

安装和初始化

bash 复制代码
# 安装 ESLint
npm install eslint --save-dev

# 初始化配置
npx eslint --init

# 交互式选择:
# - How would you like to use ESLint? → To check syntax and find problems
# - What type of modules does your project use? → JavaScript modules (import/export)
# - Which framework does your project use? → Vue.js
# - Does your project use TypeScript? → Yes
# - Where does your code run? → Browser
# - What format do you want your config file to be in? → JavaScript

Vue 3 + TypeScript 项目的最佳配置

javascript 复制代码
// .eslintrc.js
module.exports = {
  root: true,
  env: {
    browser: true,
    es2021: true,
    node: true,
    'vue/setup-compiler-macros': true
  },
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-recommended',  // 使用推荐规则
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended'    // 整合 Prettier
  ],
  parser: 'vue-eslint-parser',
  parserOptions: {
    ecmaVersion: 'latest',
    parser: '@typescript-eslint/parser',
    sourceType: 'module',
    extraFileExtensions: ['.vue']
  },
  plugins: ['vue', '@typescript-eslint'],
  rules: {
    // 关闭与 Prettier 冲突的规则
    'vue/max-attributes-per-line': 'off',
    'vue/singleline-html-element-content-newline': 'off',
    'vue/html-self-closing': 'off',
    
    // 自定义规则
    'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    
    // Vue 3 推荐
    'vue/multi-word-component-names': 'off',
    'vue/no-v-model-argument': 'off',
    
    // TypeScript
    '@typescript-eslint/no-explicit-any': 'warn',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/no-unused-vars': ['error', { 
      argsIgnorePattern: '^_' 
    }]
  },
  globals: {
    defineProps: 'readonly',
    defineEmits: 'readonly',
    defineExpose: 'readonly',
    withDefaults: 'readonly'
  }
}

自定义规则详解

javascript 复制代码
// .eslintrc.js
module.exports = {
  rules: {
    // 规则级别:off(0) 关闭 / warn(1) 警告 / error(2) 错误
    
    // ========== 最佳实践 ==========
    'eqeqeq': ['error', 'always'],  // 必须用 === 和 !==
    'no-eval': 'error',              // 禁止 eval
    'no-implied-eval': 'error',      // 禁止隐式 eval
    'no-with': 'error',              // 禁止 with 语句
    
    // ========== 变量相关 ==========
    'no-unused-vars': ['error', { 
      vars: 'all',                   // 检查所有变量
      args: 'after-used',           // 检查使用后的参数
      ignoreRestSiblings: true      // 忽略剩余参数
    }],
    'no-use-before-define': ['error', { 
      functions: false,              // 函数可以在定义前使用
      classes: true,                // 类不行
      variables: true               // 变量也不行
    }],
    
    // ========== 代码风格 ==========
    // 这些规则会被 Prettier 覆盖,但保留作为参考
    'array-bracket-spacing': ['error', 'never'],  // [1, 2, 3] 而不是 [ 1, 2, 3 ]
    'object-curly-spacing': ['error', 'always'],  // { foo: bar } 而不是 {foo: bar}
    'comma-dangle': ['error', 'never'],           // 不加尾逗号
    'quotes': ['error', 'single'],                // 用单引号
    'semi': ['error', 'never'],                   // 不加分号
    
    // ========== 复杂度控制 ==========
    'max-depth': ['warn', 4],        // 最大嵌套深度不超过4
    'max-params': ['warn', 5],        // 函数参数不超过5个
    'max-statements': ['warn', 30],    // 函数语句不超过30行
    'complexity': ['warn', 10]         // 圈复杂度不超过10
  }
}

在 package.json 中添加脚本

json 复制代码
{
  "scripts": {
    "lint": "eslint . --ext .js,.ts,.vue",
    "lint:fix": "eslint . --ext .js,.ts,.vue --fix",
    "lint:src": "eslint src --ext .js,.ts,.vue"
  }
}

Prettier - 代码美容师

什么是 Prettier?

Prettier 是格式化工具,它只有一个任务:把代码变得好看:

javascript 复制代码
// 这是我们写的(乱七八糟)
function   hello(   name   ){
console.log(   `Hello ${   name   }`   )   }

// Prettier 帮我们变成这样
function hello(name) {
  console.log(`Hello ${name}`)
}

安装与基础配置

bash 复制代码
# 安装 Prettier
npm install --save-dev prettier

# 安装 ESLint 整合插件
npm install --save-dev eslint-config-prettier eslint-plugin-prettier

Prettier 配置文件

javascript 复制代码
// .prettierrc.js
module.exports = {
  // 基础配置
  printWidth: 100,              // 每行最大宽度
  tabWidth: 2,                  // 缩进空格数
  useTabs: false,               // 用空格代替 tab
  semi: false,                  // 不加分号
  singleQuote: true,            // 用单引号
  quoteProps: 'as-needed',      // 对象属性只在必要时加引号
  trailingComma: 'none',        // 不加尾逗号
  bracketSpacing: true,         // 对象括号内加空格 { foo: bar }
  arrowParens: 'always',        // 箭头函数参数总是加括号 (x) => x
  endOfLine: 'auto',            // 自动处理换行符
  
  // Vue 相关
  vueIndentScriptAndStyle: true, // 缩进 <script> 和 <style>
  htmlWhitespaceSensitivity: 'strict',
  
  // 针对不同文件的特殊配置
  overrides: [
    {
      files: '*.vue',
      options: {
        printWidth: 120
      }
    },
    {
      files: '*.md',
      options: {
        proseWrap: 'always'
      }
    }
  ]
}

添加格式化脚本

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

编辑器集成(VS Code)

json 复制代码
// .vscode/settings.json
{
  // 保存时自动格式化
  "editor.formatOnSave": true,
  
  // 使用 Prettier 作为默认格式化工具
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  
  // 对特定文件使用不同的格式化工具
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[typescript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "[vue]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  
  // 保存时自动修复 ESLint 问题
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  
  // 禁用内置的 CSS/HTML 格式化器
  "css.validate": false,
  "scss.validate": false,
  "html.validate.scripts": false,
  "html.validate.styles": false
}

Husky + lint-staged:Git 钩子自动化

什么是 Git 钩子?

Git 钩子就像"守门员":我们在做某个 Git 操作之前,可以先执行一些检查:

text 复制代码
你想提交代码 → 守门员检查 → 没问题 → 提交成功
                 ↓
               有问题 → 不让提交,让你改

Husky 安装与配置

bash 复制代码
# 安装 Husky
npm install --save-dev husky

# 初始化 Husky(创建 .husky 目录)
npx husky install

# 添加 prepare 脚本,确保其他人安装后自动启用
npm pkg set scripts.prepare="husky install"

# 创建 pre-commit 钩子
npx husky add .husky/pre-commit "npx lint-staged"

lint-staged 配置

javascript 复制代码
// .lintstagedrc.js
module.exports = {
  // 对 JS/TS/Vue 文件运行 ESLint(并自动修复)
  '*.{js,jsx,ts,tsx,vue}': ['eslint --fix', 'prettier --write'],
  
  // 对其他文件只运行 Prettier
  '*.{json,md,yml,yaml,html,css,scss}': ['prettier --write']
}

添加提交信息规范

bash 复制代码
# 安装 commitlint
npm install --save-dev @commitlint/cli @commitlint/config-conventional

# 创建配置
cat > commitlint.config.js << 'EOF'
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        'feat',      // 新功能
        'fix',       // 修复
        'docs',      // 文档
        'style',     // 代码风格
        'refactor',  // 重构
        'perf',      // 性能优化
        'test',      // 测试
        'chore',     // 构建/工具
        'revert'     // 回滚
      ]
    ],
    'subject-full-stop': [2, 'never', '.'],  // 结尾不能有句号
    'header-max-length': [2, 'always', 100]  // 最大长度100
  }
}
EOF

# 添加 commit-msg 钩子
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

提交信息格式

bash 复制代码
# 格式
<type>(<scope>): <subject>

# 示例
feat(user): 添加用户登录功能
fix(api): 修复请求超时问题
docs(readme): 更新安装说明
style(component): 格式化代码
refactor(utils): 重构日期处理函数
perf(list): 优化列表渲染性能

完整工作流演示

日常开发流程

text 复制代码
1. 写代码
   ↓
2. 保存文件(VS Code 自动格式化)
   ↓
3. 提交代码
   ↓
4. pre-commit 钩子触发
   ↓
5. lint-staged 检查要提交的文件
   ├─ 通过 → 提交成功
   └─ 不通过 → 显示错误,拒绝提交

常见问题

场景1:提交被拦截,因为代码有问题

bash 复制代码
$ git commit -m "feat: 添加功能"
→ lint-staged 检查发现错误
→ 提交失败
解决方案:修复错误后重新提交
bash 复制代码
$ npm run lint:fix
$ git add .
$ git commit -m "feat: 添加功能"

场景2:紧急情况,跳过检查

bash 复制代码
$ git commit --no-verify -m "hotfix: 紧急修复"

CI/CD 集成

GitHub Actions 配置

yaml 复制代码
# .github/workflows/lint.yml
name: Code Quality

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  lint:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run ESLint
        run: npm run lint
      
      - name: Check formatting
        run: npm run format:check
      
      - name: Run TypeScript check
        run: npm run type-check

package.json 脚本

json 复制代码
{
  "scripts": {
    "dev": "vite",
    "build": "vue-tsc && vite build",
    "preview": "vite preview",
    
    "lint": "eslint . --ext .js,.ts,.vue",
    "lint:fix": "eslint . --ext .js,.ts,.vue --fix",
    "format": "prettier --write \"src/**/*.{js,ts,vue,json,md}\"",
    "format:check": "prettier --check \"src/**/*.{js,ts,vue,json,md}\"",
    "type-check": "vue-tsc --noEmit",
    
    "prepare": "husky install"
  }
}

常见问题与解决方案

ESLint 和 Prettier 冲突

让 Prettier 说了算:

javascript 复制代码
// .eslintrc.js
module.exports = {
  extends: [
    'plugin:vue/vue3-recommended',
    'plugin:prettier/recommended'  // 放在最后,覆盖冲突规则
  ]
}

Husky 钩子不执行

检查钩子权限:

bash 复制代码
# 1. 检查钩子文件
ls -la .husky/pre-commit

# 2. 添加执行权限
chmod +x .husky/pre-commit

# 3. 重新安装
npm run prepare

lint-staged 运行太慢

javascript 复制代码
// .lintstagedrc.js
module.exports = {
  // 方法1:限制每次检查的文件数
  '*.{js,ts,vue}': files => {
    const chunks = chunk(files, 10)
    return chunks.map(chunk => `eslint --fix ${chunk.join(' ')}`)
  },
  
  // 方法2:先跑 Prettier 再跑 ESLint
  '*.{js,ts,vue}': ['prettier --write', 'eslint --fix']
}

function chunk(arr, size) {
  return Array.from({ length: Math.ceil(arr.length / size) }, (_, i) =>
    arr.slice(i * size, i * size + size)
  )
}

新成员加入时配置不一致

bash 复制代码
# 解决方案1:提交配置文件到仓库
git add .eslintrc.js .prettierrc.js .vscode/

# 解决方案2:在 README 中说明
## 开发环境配置

1. 安装 Node.js 18+
2. 运行 `npm install`
3. 安装 VS Code 推荐插件
4. 运行 `npm run dev`

# 解决方案3:添加快速启动脚本
npm run setup

完整配置清单

项目文件结构

text 复制代码
my-project/
├── .husky/
│   ├── pre-commit          # 提交前检查
│   └── commit-msg          # 提交信息检查
├── .vscode/
│   ├── settings.json       # VS Code 设置
│   └── extensions.json     # 推荐插件
├── .eslintrc.js            # ESLint 配置
├── .prettierrc.js          # Prettier 配置
├── .lintstagedrc.js        # lint-staged 配置
├── commitlint.config.js    # 提交信息规范
├── package.json
└── README.md

快速初始化脚本

bash 复制代码
#!/bin/bash
# setup.sh - 一键配置代码规范

echo "开始配置代码规范工具链..."

# 1. 安装依赖
npm install --save-dev \
  eslint \
  prettier \
  eslint-config-prettier \
  eslint-plugin-prettier \
  eslint-plugin-vue \
  @typescript-eslint/parser \
  @typescript-eslint/eslint-plugin \
  husky \
  lint-staged \
  @commitlint/cli \
  @commitlint/config-conventional

# 2. 初始化配置文件
# (这里可以复制配置文件内容)

# 3. 初始化 Husky
npx husky install
npm pkg set scripts.prepare="husky install"
npx husky add .husky/pre-commit "npx lint-staged"
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

echo "配置完成!"

规则选择原则

  1. 不要过度约束

    • 能自动修复的用 error
    • 不能自动修复的用 warn
  2. 优先使用社区推荐

    • eslint:recommended
    • vue/vue3-recommended
  3. 团队共识优先

    • 有争议的规则,团队讨论决定
    • 少数服从多数

工具使用原则

  1. 让工具做工具的事

    • 格式化的交给 Prettier
    • 质量检查交给 ESLint
    • 提交检查交给 Git 钩子
  2. 减少手动操作

    • 保存时自动格式化
    • 提交前自动检查
    • CI 自动验证
  3. 允许特殊情况

    • 可以用 --no-verify 跳过
    • 可以用 eslint-disable 忽略
    • 可以用 prettier-ignore 忽略

团队协作建议

  1. 配置纳入版本控制

    • 所有配置文件提交到仓库
    • 新人 clone 后直接可用
  2. 做好文档

    • README 说明如何配置
    • 记录特殊规则的原因
  3. 定期回顾

    • 收集反馈
    • 调整规则
    • 持续优化

结语

工具是辅助,不是目的。代码规范的核心是提升团队效率和代码质量,而不是制造障碍。自动化的代码规范工具链,不是为了限制开发者,而是为了解放开发者。让工具处理那些可以自动化的琐事,让人专注于真正需要思考的业务逻辑。

对于文章中错误的地方或有任何疑问,欢迎在评论区留言讨论!

相关推荐
xiangpanf2 小时前
PHP与Vue:前后端技术深度对比
开发语言·vue.js·php
小同志002 小时前
HTML 基础
前端·javascript·html
wuhen_n4 小时前
网络请求在Vite层的代理与Mock:告别跨域和后端依赖
前端·javascript·vue.js
小彭努力中4 小时前
193.Vue3 + OpenLayers 实战:圆孔相机模型推算卫星拍摄区域
vue.js·数码相机·vue·openlayers·geojson
用户69371750013848 小时前
Google 正在“收紧侧加载”:陌生 APK 安装或需等待 24 小时
android·前端
蓝帆傲亦9 小时前
Web 前端搜索文字高亮实现方法汇总
前端
用户69371750013849 小时前
Room 3.0:这次不是升级,是重来
android·前端·google