人人都会AI编程

19.2 Husky + lint-staged + commitlint:提交前校验与提交规范

更新时间:2026-07-09

代码质量的控制,不能只靠“自觉”。即使团队配置了 ESLint 和 Prettier,成员也很容易忘记执行——或者直接 git commit 把未格式化的代码推上仓库。用 Huskylint-stagedcommitlint 这三件套,就能在 Git 工作流的关键节点自动卡住不规范的操作。

三件套的分工

  • Husky:用来监听 Git 钩子(hooks),比如在 git commit 之前自动执行某些命令。
  • lint-staged:只对 Git 暂存区(staged)的文件运行检查,速度快且精准——你不会因为历史遗留的一万个报错而阻塞这次提交。
  • commitlint:约束 commit message 的格式,让每一次提交都遵循统一的规范(如 Conventional Commits)。

三者配合的典型流程是:
git commit → Husky 触发 pre-commit 钩子 → lint-staged 对暂存文件执行校验和格式化 → 校验通过后进入 commit-msg 钩子 → commitlint 检查 commit message 是否符合规范 → 通过则提交成功。

安装与初始化

在已有的 Vue 项目中执行:

# 安装依赖
npm install --save-dev husky lint-staged @commitlint/cli @commitlint/config-conventional

然后初始化 Husky:

npx husky init

这条命令会在项目根目录创建 .husky 文件夹,里面包含 pre-commit 钩子脚本,并自动把 package.json 中的 scripts 加上 prepare 脚本(用于合作者 npm install 时自动启用 Git 钩子)。

配置 lint-staged

在项目根目录创建 .lintstagedrc 文件(或干脆写在 package.jsonlint-staged 字段里):

{
  "src/**/*.{js,jsx,ts,tsx,vue}": [
    "eslint --fix",
    "prettier --write"
  ],
  "src/**/*.{css,scss,less,html}": [
    "prettier --write"
  ]
}

这段配置的意思是:只对暂存区中匹配的文件,先用 ESLint 修复,再用 Prettier 格式化。如果其中有任一命令报错(比如 ESLint 存在无法自动修复的 error),整个提交就会被中止。

注意:prettier --writeeslint --fix 的顺序要留意,避免互相覆盖规则。通常可以在 ESLint 配置中关闭与 Prettier 冲突的规则(通过 eslint-config-prettier),让 Prettier 只做风格格式化,ESLint 只检查代码质量。

配置 commitlint

创建 commitlint.config.js

export default {
  extends: ['@commitlint/config-conventional'],
  rules: {
    // 可以自定义规则,比如要求类型必须为指定列表之一
    'type-enum': [
      2,
      'always',
      ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'chore', 'ci', 'revert']
    ]
  }
}

这里继承了 @commitlint/config-conventional,它规定了形如 type(scope?): description 的提交格式。例如:

feat: 添加用户登录功能
fix(user): 修正头像上传失败的问题

不符合规范的提交(比如 修改了bugupdate code)会被直接拒绝,并提示修改。

编写 Husky 钩子脚本

.husky/pre-commit 文件中写入(初始化 husky 时一般已自动生成基本内容,如果没有就自己创建):

#!/usr/bin/env sh
npx lint-staged

.husky/commit-msg 文件中写入:

#!/usr/bin/env sh
npx --no-install commitlint --edit $1

--no-install 告诉 husky 不要自动安装依赖(避免多次 npx 安装的延迟),$1 是 git 传给钩子的临时 commit message 文件路径。

效果演示

假设一个开发者写了一段破坏代码质量的逻辑:

<template>
  <div>
    <p>{{message}}</p>
  </div>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('hello')
</script>

并且没有执行 ESLint/Prettier,直接执行 git add . && git commit -m "修改了界面"。此时:

  • pre-commit 钩子触发→ lint-staged 运行 ESLint,发现模版中 {{message}} 缺少空格(规则要求插值表达式内首尾有空格),ESLint 报错并中止。
  • 即便修复了代码格式,第二个钩子 commit-msg 会检测到“修改了界面”不符合 Conventional Commits 规范,也会拒绝提交,并提示信息格式错误。

开发者将 commit message 改为 style: 修正模板插值空格 后提交成功。

为什么这套方案“实用又真实”

  • 只卡暂存文件:lint-staged 加上文件匹配,每次提交的检查时间不过几秒,不把整个项目的历史负担带进来。
  • 自动化格式化:无需手动跑命令,代码在提交前自动变整洁,不会有人“忘记格式化”。
  • 强制信息规范:好的 commit message 是自动生成 CHANGELOG、语义化版本号以及快速定位问题的基石。
  • 团队零学习成本:配置一次后永久生效,对于新成员只会在第一次不规范提交时收到友好提示,自然养成习惯。

在整个 Vue 工程化体系中,这套“提交门禁”是第 19 章代码规范的落地执行者。它和 ESLint/Prettier 组合在一起,构成了从编码到仓库的健康防线,让项目在多人协作下依然保持代码清晰、历史可读。