本文面向 React 19 + Vite 的前端工程化场景,目标是让团队在每次提交时自动完成:

  • 代码格式化:Prettier 统一代码风格
  • 代码质量修复:ESLint 在提交前对暂存文件自动 --fix
  • 提交说明规范:Commitlint 校验提交信息(Conventional Commits)

本方案使用:

  • simple-git-hooks:把钩子脚本写入仓库的 .git/hooks/
  • lint-staged:只对 暂存区 文件运行 ESLint/Prettier(避免全量扫描)
  • commitlint:在 commit-msg 钩子校验提交说明
  • (可选)Commitizen + cz-git:交互式生成符合规范的提交说明

如果你只想了解“当前仓库里这些配置如何协作/如何排查”,请看 frontend/docs/git-hooks.md

流程图

提交流程

或直接 git commit -m

git add

git commit

gcIn

pre-commit 钩子

lint-staged

eslint / prettier

通过?

提交中断

commit-msg 钩子

commitlint

说明合规?

提交中断

提交成功

安装与生成钩子

pnpm install

prepare 生命周期

simple-git-hooks

写入 .git/hooks

图例简要@commitlint/config-conventional 为 Commitlint 提供默认规则集;commitizen 提供 git-cz 入口,交互由 cz-git 完成。先完成左侧“安装并生成 .git/hooks”,右侧提交流程才会在每次 git commit 时自动执行。


前置条件

  • 仓库已初始化 Git(存在 .git/)。
  • 包含前端 package.json 的目录执行安装与脚本(本仓库为 frontend/)。
  • 已安装 pnpm(下文以 pnpm 为例;如团队使用 npm/yarn,可自行等价替换)。

步骤 1:安装开发依赖

在目标目录(例如 frontend/)执行:

pnpm add -D simple-git-hooks lint-staged @commitlint/cli @commitlint/config-conventional

上述依赖分工如下:

包名 作用
simple-git-hooks 根据 package.json"simple-git-hooks" 配置,把要执行的命令写入仓库 .git/hooks/(如 pre-commitcommit-msg);配合 prepare 让协作者安装依赖后自动同步钩子。
lint-staged 仅对 Git 暂存区 文件按 glob 运行命令(如 eslint、prettier);通常挂在 pre-commit 钩子里,避免全仓库扫描、加快提交前检查。
@commitlint/cli 提供 commitlint 命令行:在 commit-msg 钩子里读取本次提交说明并按规则校验;不通过则提交失败。
@commitlint/config-conventional Commitlint 的预设规则包,对应常见 Conventional Commits(如 featfix 等类型前缀);在 .commitlintrc.js 中通过 extends 引用。

提交前“格式化 + 修复”还需要 ESLintPrettier。本仓库已在 frontend 里完成配置;如果你在其他项目从零搭建,请先把这两者安装并配置好。

步骤 1 补充:ESLint、TypeScript 与 Prettier

lint-staged 里会调用 eslintprettier 命令,因此这两个工具必须已安装到 devDependencies,且仓库根(本仓库为 frontend/)下存在可被发现的可执行文件(通常即 node_modules/.bin)。

安装命令(从零对齐本仓库版本范围)

frontend/(或你的前端包根目录)执行:

pnpm add -D \
  eslint@^9.33.0 \
  @eslint/js@^9.33.0 \
  typescript-eslint@^8.39.1 \
  typescript@~5.8.3 \
  eslint-config-airbnb-base@^15.0.0 \
  eslint-config-prettier@^10.1.8 \
  eslint-plugin-import@^2.32.0 \
  eslint-plugin-react@^7.37.5 \
  eslint-plugin-react-hooks@^5.2.0 \
  eslint-plugin-react-refresh@^0.4.20 \
  globals@^16.3.0 \
  prettier@^3.6.2

根目录下新建 eslint.config.js 配置文件

import js from "@eslint/js";
import airbnbBase from "eslint-config-airbnb-base";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import { defineConfig } from "eslint/config";
import globals from "globals";
import tseslint from "typescript-eslint";

export default defineConfig([
  js.configs.recommended,
  ...tseslint.configs.recommended,
  {
    ignores: ["dist/**", "src/assets/*.js"],
  },
  {
    files: ["**/*.{ts,tsx,js,jsx}"],
    languageOptions: {
      ecmaVersion: 2020,
      globals: globals.browser,
      parserOptions: {
        ecmaFeatures: {
          jsx: true,
        },
      },
    },
    plugins: {
      "react-hooks": reactHooks,
      "react-refresh": reactRefresh,
    },
    rules: {
      // 合并 Airbnb Base 规则
      ...airbnbBase.rules,
      // React Hooks 规则
      ...reactHooks.configs.recommended.rules,
      // React Refresh 规则
      ...reactRefresh.configs.vite.rules,
      // 空行规则
      "lines-between-class-members": ["error", "always"],
      "padding-line-between-statements": [
        "error",
        // 在 export 语句前添加空行
        { blankLine: "always", prev: "*", next: "export" },
        // 在函数声明前后添加空行
        { blankLine: "always", prev: "*", next: "function" },
        { blankLine: "always", prev: "function", next: "*" },
        // 在 return 语句前添加空行
        { blankLine: "always", prev: "*", next: "return" },
        // 在 if/for/while 语句前添加空行
        {
          blankLine: "always",
          prev: "*",
          next: ["if", "for", "while", "switch"],
        },
      ],
      // 其他代码质量规则
      "no-multiple-empty-lines": ["error", { max: 2, maxEOF: 1 }],
      "no-trailing-spaces": "error",
      "eol-last": ["error", "always"],
      // 允许使用 any 类型
      "@typescript-eslint/no-explicit-any": "off",
      // 允许单个下划线作为未使用变量
      "@typescript-eslint/no-unused-vars": [
        "error",
        {
          argsIgnorePattern: "^_$",
          varsIgnorePattern: "^_$",
          caughtErrorsIgnorePattern: "^_$",
        },
      ],
      "react-hooks/exhaustive-deps": "off",
    },
  },
]);

包名 作用
eslint / @eslint/js ESLint 9 核心与官方 JS 推荐规则基线
typescript-eslint TypeScript 解析与 @typescript-eslint/* 推荐规则
typescript 类型检查与解析器依赖(版本与团队 tsconfig 对齐即可)
eslint-config-airbnb-base Airbnb 基础风格(本仓库在 eslint.config.js 中合并其 rules
eslint-plugin-import airbnb-base 依赖的 import 相关规则
eslint-plugin-react / react-hooks / react-refresh React 19 + Vite 场景下的组件、Hooks 与 HMR 约束
globals 声明 window 等浏览器全局,避免误报 no-undef
eslint-config-prettier 关闭与 Prettier 冲突的 ESLint 格式类规则;在 flat config 中必须作为最后一项合并(见下)
prettier 独立格式化器,由 lint-staged 在 ESLint --fix 之后执行

可选(交互式写提交说明):

pnpm add -D commitizen cz-git
包名 作用
commitizen 提供 git-cz(通常映射为 pnpm run commit)的交互式提交流程入口。
cz-git Commitizen 的适配器,可在 .commitlintrc.js 中统一配置中文提示、类型列表,并与 commitlint 规则对齐。

步骤 2:添加 prepare 脚本

package.jsonscripts 中加入(prepare 是 npm 生命周期脚本名,用于“安装依赖后自动执行”):

"prepare": "simple-git-hooks"

步骤 3:声明 simple-git-hooks 钩子命令

package.json 根级增加与 scripts 平级的字段,例如与本项目一致:

  • “pre-commit”: 在提交代码之前执行 lint-staged,对暂存的文件运行 ESLint 和 Prettier 修复/格式化
  • “commit-msg”: 在提交信息被保存时执行 commitlint,依据 .commitlintrc.js 配置校验提交说明规范,$1 表示提交信息文件路径
"simple-git-hooks": {
  "pre-commit": "npx lint-staged",
  "commit-msg": "npx commitlint --config .commitlintrc.js --edit $1"
}

说明:

  • pre-commit:提交前执行 lint-staged(见步骤 5)。
  • commit-msg:提交时校验说明;$1 为 Git 传入的提交信息文件路径。若在个别 Windows shell 下异常,优先参考 simple-git-hooks / commitlint 的 Windows 说明,或统一在 Git Bash / WSL 环境执行。

按需可增加其他钩子(如 pre-push),键名与 Git 钩子文件名对应。


步骤 4:配置 Prettier(用于代码格式化)

若项目尚未安装 Prettier:

pnpm add -D prettier

创建 .prettierrc

  • singleQuote: 是否使用单引号。false 表示用双引号。
  • trailingComma: 末尾逗号策略。all 表示对象/数组等都加尾逗号。
  • printWidth: 每行最大字符数。超过会自动换行,常用 80。
  • tabWidth: 缩进空格数,2 代表每级缩进2个空格。
  • semi: 语句末是否添加分号。true 表示结尾加分号。
{
  "singleQuote": false,
  "trailingComma": "all",
  "printWidth": 80,
  "tabWidth": 2,
  "semi": true
}

创建 .prettierignore(示例与本仓库一致):

node_modules/
dist/

说明:本仓库已包含 frontend/.prettierrcfrontend/.prettierignore,你通常不需要重复创建;这里用于“从零搭建”时对齐配置。


步骤 5:配置 lint-staged(提交前只处理暂存文件)

package.json 根级增加 lint-staged 字段,按文件类型声明命令。与本项目一致时可采用:

  • JS/TS/HTML 文件:先通过 eslint 自动修复再用 prettier 格式化
  • 样式文件:仅用 prettier 格式化
  • Markdown、JSON、YAML:仅用 prettier 格式化
"lint-staged": {
  "*.{js,jsx,ts,tsx,html}": [
    "eslint --fix",
    "prettier --write"
  ],
  "*.{css,scss,less}": [
    "prettier --write"
  ],
  "*.{md,json,yml,yaml}": [
    "prettier --write"
  ]
}

可按技术栈增删 glob 或命令(例如仅 Prettier、或增加 stylelint)。


步骤 6:添加 Commitlint 配置

package.json 同级新建 .commitlintrc.js(或 .commitlintrc.cjs 等,需与步骤 3 中 --config 路径一致)。

最小可用示例(继承 Conventional Commits):

export default {
  extends: ["@commitlint/config-conventional"],
};

常用规则样例(可直接复制后按团队规范调整):

export default {
  extends: ["@commitlint/config-conventional"],
  rules: {
    // 允许的提交类型(与 Conventional Commits / cz-git 常用类型对齐)
    "type-enum": [
      2,
      "always",
      [
        "feat",
        "fix",
        "docs",
        "style",
        "refactor",
        "perf",
        "test",
        "build",
        "ci",
        "chore",
        "revert",
      ],
    ],

    // header 总长度限制(如:feat(login): add remember me)
    "header-max-length": [2, "always", 100],

    // scope 规则:可选;如果你们要求必须写 scope,把 0 改成 2
    "scope-empty": [0, "never"],

    // subject 规则:不允许句号结尾;且至少有内容
    "subject-empty": [2, "never"],
    "subject-full-stop": [2, "never", "."],

    // subject 大小写:多数团队会放宽(允许中文/任意大小写)
    "subject-case": [0, "never"],
  },
};

本仓库在此基础上使用了 cz-git 的 defineConfig、自定义 rules 与中文 prompt,可直接参考 frontend/.commitlintrc.js 按需裁剪。


步骤 7(可选):Commitizen + cz-git

package.json 中增加:

"scripts": {
  "commit": "git-cz"
},
"config": {
  "commitizen": {
    "path": "node_modules/cz-git"
  }
}

日常执行 pnpm run commit 按向导填写类型与描述,减少手写格式错误。


步骤 8:生成钩子文件

任选其一:

  1. 推荐:执行依赖安装(会触发 prepare):
 pnpm install
  1. 手动执行:
 npx simple-git-hooks

完成后,仓库 .git/hooks/ 下应出现(或更新)pre-commitcommit-msg 等脚本。


步骤 9:自测(验证会自动格式化/修复)

  1. 修改若干文件并 git add
  2. 执行 git commit(或 pnpm run commit),确认:
  • pre-commit 会运行 lint-staged(可能会自动改动文件并要求你重新 git add)。
  • commit-msg 会校验提交说明;故意写不符合规范的 message 时应失败。

修改配置后(如何让钩子更新)

若更新了 simple-git-hookslint-staged 等字段,请重新执行 pnpm installnpx simple-git-hooks,使 .git/hooks 与最新配置一致。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐