📚 现代前端开发 目录
阶段2:工程化
第 13 / 35 课

代码规范:ESLint与Prettier

统一团队代码风格

📖 核心概念

💻 代码实现

ESLint配置 ✅ javascript
// eslint.config.js (Flat Config - ESLint 9+)
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import reactPlugin from 'eslint-plugin-react';
import reactHooks from 'eslint-plugin-react-hooks';
import prettier from 'eslint-config-prettier';

export default tseslint.config(
  // 全局忽略
  { ignores: ['dist/', 'node_modules/', '*.min.js'] },

  // 基础推荐规则
  js.configs.recommended,

  // TypeScript规则
  ...tseslint.configs.recommended,

  // React规则
  {
    files: ['**/*.{ts,tsx}'],
    plugins: {
      react: reactPlugin,
      'react-hooks': reactHooks,
    },
    rules: {
      ...reactPlugin.configs.recommended.rules,
      ...reactPlugin.configs['jsx-runtime'].rules,
      ...reactHooks.configs.recommended.rules,
      'react/prop-types': 'off',
      'react/react-in-jsx-scope': 'off',
    },
    settings: {
      react: { version: 'detect' },
    },
  },

  // 自定义规则覆盖
  {
    files: ['src/**/*.{ts,tsx}'],
    rules: {
      'no-console': ['warn', { allow: ['warn', 'error'] }],
      'no-unused-vars': 'off',
      '@typescript-eslint/no-unused-vars': ['error', {
        argsIgnorePattern: '^_',
        varsIgnorePattern: '^_',
      }],
      '@typescript-eslint/explicit-function-return-type': ['error', {
        allowExpressions: true,
        allowTypedFunctionExpressions: true,
      }],
      '@typescript-eslint/consistent-type-imports': ['error', {
        prefer: 'type-imports',
      }],
      '@typescript-eslint/no-non-null-assertion': 'error',
      'react-hooks/exhaustive-deps': 'error',
    },
  },

  // 测试文件宽松规则
  {
    files: ['**/*.test.{ts,tsx}', '**/*.spec.{ts,tsx}'],
    rules: {
      '@typescript-eslint/no-explicit-any': 'off',
      '@typescript-eslint/explicit-function-return-type': 'off',
    },
  },

  // Prettier兼容(必须放最后)
  prettier,
);
Prettier与Git Hooks ✅ javascript
// .prettierrc
{
  "semi": true,
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100,
  "tabWidth": 2,
  "bracketSpacing": true,
  "arrowParens": "always",
  "endOfLine": "lf",
  "overrides": [
    {
      "files": "*.json",
      "options": { "printWidth": 200 }
    },
    {
      "files": "*.md",
      "options": { "proseWrap": "always" }
    }
  ]
}

// .prettierignore
// dist/
// node_modules/
// *.min.js
// package-lock.json

// package.json - lint-staged配置
// {
//   "lint-staged": {
//     "*.{ts,tsx}": [
//       "eslint --fix",
//       "prettier --write"
//     ],
//     "*.{json,md,yml}": [
//       "prettier --write"
//     ],
//     "*.css": [
//       "stylelint --fix",
//       "prettier --write"
//     ]
//   }
// }

// 设置husky
// pnpm dlx husky init
// echo "pnpm exec lint-staged" > .husky/pre-commit

// 自定义ESLint规则示例
// rules/no-inline-styles.js
export default {
  meta: {
    type: 'suggestion',
    docs: { description: '禁止内联样式' },
    messages: {
      noInlineStyles: '请使用CSS类代替内联样式,便于维护和复用',
    },
  },
  create(context) {
    return {
      JSXAttribute(node) {
        if (node.name.name === 'style') {
          context.report({ node, messageId: 'noInlineStyles' });
        }
      },
    };
  },
};

🔍 代码规范落地实践

规范的制定容易,执行难。成功落地的关键:从最基础的规则开始,逐步收紧;让工具自动执行,不依赖人工检查;在CI中强制执行,不通过的PR不能合并;定期review规则,移除不再适用的规则。团队成员的认同比规则本身更重要。

🔍 ESLint Flat Config迁移指南

从ESLint 8的.eslintrc迁移到ESLint 9的Flat Config(eslint.config.js)是2024年的重要变更。主要变化:配置从JSON对象变为JS数组、插件引用方式改变、忽略模式使用ignores属性。迁移步骤:1) 安装@eslint/migrate-config兼容旧配置;2) 逐步将规则迁移到新格式;3) 测试确保规则行为一致。Flat Config的优势:更好的性能、更清晰的配置合并、原生ESM支持。

🎯 练习任务

🏆 成就解锁
规范守护者 — 建立团队代码规范体系,让代码风格统一一致