前端工程化最佳实践:ESLint+Prettier+Git Hooks 统一开发规范

前端工程化最佳实践:ESLint+Prettier+Git Hooks 统一开发规范


目标与收益

  • 一致风格与质量:统一代码风格、导入顺序与常见错误拦截
  • 提交即校验:在提交阶段自动修复与拦截不合规改动
  • 持续集成:CI 对齐本地规则,保证主干稳定

安装与基础脚本

bash 复制代码
pnpm i -D eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint-plugin-vue eslint-plugin-react eslint-plugin-import eslint-plugin-simple-import-sort
pnpm i -D prettier eslint-config-prettier eslint-plugin-prettier
pnpm i -D husky lint-staged @commitlint/cli @commitlint/config-conventional

package.json 脚本与 lint-staged:

json 复制代码
{
  "scripts": {
    "lint": "eslint --ext .ts,.tsx,.js,.vue src",
    "lint:fix": "eslint --ext .ts,.tsx,.js,.vue src --fix",
    "format": "prettier --write .",
    "test": "vitest run || jest"
  },
  "lint-staged": {
    "src/**/*.{ts,tsx,js,vue}": ["eslint --fix", "prettier --write"],
    "src/**/*.{css,scss,md}": ["prettier --write"]
  }
}

ESLint 配置(TS + Vue/React 通用示例)

.eslintrc.cjs

js 复制代码
module.exports = {
  root: true,
  env: { browser: true, es2021: true, node: true },
  parser: '@typescript-eslint/parser',
  parserOptions: { ecmaVersion: 'latest', sourceType: 'module' },
  plugins: ['@typescript-eslint', 'import', 'simple-import-sort', 'prettier'],
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:vue/vue3-recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:import/recommended',
    'plugin:import/typescript',
    'prettier'
  ],
  settings: { react: { version: 'detect' } },
  rules: {
    'prettier/prettier': ['error'],
    'import/order': ['off'],
    'simple-import-sort/imports': ['error'],
    'simple-import-sort/exports': ['error'],
    '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
    'vue/multi-word-component-names': 'off'
  },
  overrides: [
    { files: ['**/*.vue'], rules: { 'react/jsx-uses-react': 'off', 'react/react-in-jsx-scope': 'off' } },
    { files: ['**/*.tsx'], rules: { 'vue/no-unused-components': 'off' } }
  ]
}

Prettier 配置

.prettierrc.json

json 复制代码
{ "semi": false, "singleQuote": true, "printWidth": 100, "trailingComma": "es5" }

可选 .editorconfig

ini 复制代码
root = true
[*]
indent_style = space
indent_size = 2
charset = utf-8
end_of_line = lf
insert_final_newline = true

Git Hooks(Husky)

初始化与钩子:

bash 复制代码
npx husky init

.husky/pre-commit

sh 复制代码
npx lint-staged

.husky/commit-msg

sh 复制代码
npx commitlint --edit "$1"

.husky/pre-push

sh 复制代码
pnpm test

commitlint.config.cjs

js 复制代码
module.exports = { extends: ['@commitlint/config-conventional'] }

提交信息示例:

text 复制代码
feat(auth): 支持短信验证码登录
fix(router): 修复刷新后白屏问题
chore(deps): 升级 eslint 到最新版本

Monorepo 与工作区建议

  • 使用 pnpm workspaces 与 Turbo/Changesets 管理多包;在根目录统一 ESLint/Prettier 配置
  • lint-staged 可在根目录配置并针对各包的 src/ 路径匹配
  • 在 CI 中按变更范围运行 lint/test(如 Turbo pipeline lint/test

CI 配置(GitHub Actions)

.github/workflows/quality.yml

yaml 复制代码
name: Quality
on: { pull_request: { branches: [main] }, push: { branches: [main] } }
jobs:
  lint_test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20', cache: 'pnpm' }
      - run: corepack enable
      - run: pnpm i --frozen-lockfile
      - run: pnpm lint
      - run: pnpm test -- --coverage

规则扩展与导入排序

  • 导入排序统一:simple-import-sort 以组为单位排序,避免冲突
  • 不同栈规则:Vue 项目开启 plugin:vue/vue3-recommended;React 项目开启 react-hooks 规则
  • 忽略与例外:对自动生成文件与构建产物设置 .eslintignore.prettierignore

.eslintignore.prettierignore

text 复制代码
dist
node_modules
coverage
*.min.js

常见坑与修复

  • ESLint 与 Prettier 冲突:确保 extends 中最后是 prettier,开启 prettier/prettier 错误级别
  • Husky 不生效:确认 .husky 目录在仓库根且钩子文件可执行;在 CI 环境只执行脚本不启用钩子
  • lint-staged 过慢:控制匹配范围与并发;避免在钩子里运行全量测试
  • 多栈共存:通过 overrides 针对 .vue.tsx 设置规则差异

IDE 集成与本地一致性

json 复制代码
{
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": { "source.fixAll.eslint": true },
  "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact", "vue" ]
}

提交规范与自动发布(可选)

feat 映射 minorfix 映射 patch、含 BREAKING CHANGE 映射 major

Changesets 或 semantic-release 可自动生成版本与变更日志。

性能优化与门禁

json 复制代码
{
  "lint-staged": {
    "src/**/*.{ts,tsx,js,vue}": ["eslint --fix --cache", "prettier --write"],
    "*.{css,scss,md}": ["prettier --write"]
  }
}
json 复制代码
{
  "coverageThreshold": { "global": { "branches": 70, "functions": 70, "lines": 70 } }
}

规则模板与扩展建议

  • Vue:vue/no-mutating-propsvue/require-prop-types
  • React:react/jsx-no-useless-fragmentreact/no-array-index-keyreact-hooks/exhaustive-deps
  • 样式与测试:按需加入 stylelinteslint-plugin-jest@testing-library/eslint-plugin

规范约束矩阵(示例)

  • 代码风格:Prettier 统一;ESLint 禁止未用变量与未排序导入
  • 提交信息:Conventional Commits(type(scope): subject)
  • 质量门禁:pre-commit 运行 lint-staged;pre-push 运行测试;CI 覆盖率阈值
  • 编辑器一致性:保存即格式化与自动修复;统一换行与缩进

commitlint 高级配置(示例)

commitlint.config.cjs

js 复制代码
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [2, 'always', ['feat','fix','chore','docs','refactor','perf','test','build','ci','revert']],
    'scope-enum': [2, 'always', ['app','ui','api','deps','lint','release']],
    'subject-case': [2, 'never', ['sentence-case','start-case','pascal-case','upper-case']],
    'header-max-length': [2, 'always', 72]
  }
}

导入排序自定义分组

.eslintrc.cjs 片段:

js 复制代码
rules: {
  'simple-import-sort/imports': ['error', {
    groups: [
      ['^react', '^vue', '^@?\w'],
      ['^(@/)(.*)$'],
      ['^\.\.(?!/?$)', '^\.'],
      ['^.+\.s?css$']
    ]
  }]
}

行尾与换行一致性

.gitattributes

text 复制代码
* text=auto eol=lf

统一跨平台换行(LF),避免格式化差异。

lint-staged 性能优化

在钩子中开启 ESLint 缓存、控制并发与匹配范围:

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

迁移步骤(落地)

  • 第一步:在根目录新增 ESLint/Prettier/commitlint 配置与忽略文件
  • 第二步:初始化 Husky 与 lint-staged,开启 pre-commit/commit-msg/pre-push
  • 第三步:在 CI 增加质量工作流(lint/test/coverage)
  • 第四步:统一编辑器设置与扩展,保存即格式化
  • 第五步:每月回顾规则与规范产出,按反馈迭代(新增或降低规则级别)

落地清单(10 项)

  • 在根目录统一 ESLint/Prettier 配置并落库
  • 初始化 Husky 并启用 pre-commit/commit-msg/pre-push
  • 配置 lint-staged 针对源码目录匹配
  • 引入 commitlint 并规范提交信息
  • 为导入排序与未用变量设定统一规则
  • 设置 ignore 列表,避免构建产物被格式化
  • 在 CI 中运行 linttest 并采集覆盖率
  • 为 Monorepo 统一配置并按变更范围运行管线
  • 在编辑器启用 ESLint 与 Prettier 扩展(保存即格式化)
  • 每月回顾规则与产出,按团队反馈迭代

总结

  • 通过 ESLint+Prettier+Git Hooks 的组合,在提交与 CI 阶段统一质量门禁
  • 配合导入排序、类型规则与提交规范,团队可持续保持高一致性与低维护成本
相关推荐
恋猫de小郭4 小时前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
崔庆才丨静觅11 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby606112 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了12 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅12 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅12 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
李少兄13 小时前
在 IntelliJ IDEA 中修改 Git 远程仓库地址
java·git·intellij-idea
崔庆才丨静觅13 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment13 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅13 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端