Skip to content

Husky 配置指南

本文档详细介绍了在 Blog 项目中配置 Husky 的完整过程,包括代码质量检查、提交信息规范、自动化部署等最佳实践。

本指南基于 Blog 项目的实际落地经验总结,适用于 VitePress 静态站点项目。

什么是 Git Hooks

Git hooks 是在 Git 执行特定操作时自动运行的脚本。常用的 hooks 包括:

  • pre-commit: 在提交前执行,用于代码检查和格式化
  • commit-msg: 在提交信息创建后执行,用于验证提交信息格式
  • pre-push: 在推送前执行,用于最终检查和自动化部署

Husky

Husky 是一个 Git hooks 工具,它可以让你在 Git 操作的特定时机自动执行脚本。

主要优势

  1. 代码质量保证: 在代码提交前自动执行 ESLint、Prettier 等工具
  2. 提交规范: 强制执行 Conventional Commits 规范
  3. 团队协作: 确保所有团队成员遵循相同的代码标准
  4. 自动化: 减少手动检查,提高开发效率
  5. 错误预防: 在代码进入仓库前发现并修复问题

使用场景

  • 多人协作项目: 确保代码风格一致性
  • 持续集成/持续部署: 在提交代码前进行自动化检查和部署
  • 代码审查: 提高 PR 质量,减少审查时间
  • 规范化开发: 建立标准化的开发流程
  • 自动化部署: 结合 pre-push hook 实现推送即部署

实现过程

1. 安装依赖

首先安装必要的开发依赖:

bash
pnpm add -D husky lint-staged @commitlint/cli @commitlint/config-conventional eslint prettier

依赖说明

  • husky: Git hooks 管理工具
  • lint-staged: 对暂存文件执行脚本
  • @commitlint/cli: 提交信息检查工具
  • @commitlint/config-conventional: Conventional Commits 规范配置
  • eslint: JavaScript/TypeScript 代码检查工具
  • prettier: 代码格式化工具

2. 初始化 Husky

bash
pnpm exec husky init

这个命令会:

  • 创建 .husky 目录
  • 生成基础的 hook 文件
  • package.json 中添加 prepare 脚本:"prepare": "husky"

3. 配置文件创建

3.1 创建 Commitlint 配置

创建 commitlint.config.cjs(如果项目是 ESM,建议使用 .cjs 后缀):

javascript
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'body-leading-blank': [1, 'always'],
    'body-max-line-length': [2, 'always', 100],
    'footer-leading-blank': [1, 'always'],
    'footer-max-line-length': [2, 'always', 100],
    'header-max-length': [2, 'always', 120],
    'scope-case': [2, 'always', 'lower-case'],
    'subject-case': [2, 'never', []],
    'subject-empty': [2, 'never'],
    'subject-full-stop': [2, 'never', '.'],
    'type-case': [2, 'always', 'lower-case'],
    'type-empty': [2, 'never'],
    'type-enum': [
      2,
      'always',
      [
        'build', // 构建系统或外部依赖的更改
        'chore', // 其他修改
        'ci', // CI 配置文件和脚本的更改
        'docs', // 文档修改
        'feat', // 新功能
        'fix', // 修复 bug
        'perf', // 性能优化
        'refactor', // 代码重构
        'revert', // 回滚
        'style', // 代码格式
        'test' // 测试
      ]
    ]
  }
}

3.2 Prettier 配置

创建 .prettierrc.cjs

javascript
module.exports = {
  singleQuote: true, // 使用单引号
  trailingComma: 'all', // 尾随逗号
  printWidth: 100, // 每行最大长度
  semi: true, // 使用分号
  tabWidth: 2, // 缩进宽度
  endOfLine: 'lf', // 换行符(Unix)
  arrowParens: 'always' // 箭头函数参数括号
}

3.3 Lint-staged 配置

package.json 中添加:

json
{
  "lint-staged": {
    "**/*.{js,ts,vue}": ["prettier --write", "eslint --fix"],
    "**/*.{md,json}": ["prettier --write"]
  }
}

说明

  • 对 JS/TS/Vue 文件:先格式化,再 ESLint 检查和修复
  • 对 Markdown/JSON 文件:只进行格式化

3.4 忽略文件配置

创建 .prettierignore

# 依赖
node_modules
pnpm-lock.yaml

# 构建产物
dist
.vitepress/dist
.vitepress/cache

# 日志
*.log
logs

# 系统文件
.DS_Store

创建 .eslintignore(如果需要):

node_modules
dist
.vitepress/dist
.vitepress/cache

Hook 脚本配置

4.1 Pre-commit Hook

创建 .husky/pre-commit

bash
npx lint-staged

作用:在提交前对暂存的文件执行 Prettier 格式化和 ESLint 检查

4.2 Commit-msg Hook

创建 .husky/commit-msg

bash
npx --no -- commitlint --edit $1

作用:验证提交信息是否符合 Conventional Commits 规范

4.3 Pre-push Hook(可选,用于自动化部署)

创建 .husky/pre-push

bash
#!/bin/bash

echo "🚀 检测到push操作..."

# 只对main分支生效
current_branch=$(git symbolic-ref --short HEAD)
if [ "$current_branch" != "main" ]; then
  echo "📝 当前分支: $current_branch,跳过部署检查"
  exit 0
fi

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📋 部署前检查"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "   1. 代码已通过lint检查 ✓"
echo "   2. 提交信息规范 ✓"
echo "   3. 分支: main ✓"
echo ""

# 询问是否部署
read -p "是否部署到生产环境?(y/n) " -n 1 -r
echo ""

if [[ ! $REPLY =~ ^[Yy]$ ]]; then
  echo ""
  echo "⏸️  跳过部署,继续push"
  echo ""
  echo "⚠️  注意:代码将推送但不会部署到服务器"
  echo "💡 稍后手动部署:pnpm run deploy"
  echo ""
  exit 0
fi

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🚀 开始自动部署"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

# 执行部署脚本
./scripts/deploy.sh

# 检查部署结果
if [ $? -ne 0 ]; then
  echo ""
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  echo "❌ 部署失败,push已终止"
  echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
  echo ""
  echo "📋 查看失败原因:"
  echo "   pnpm run deploy:logs"
  echo ""
  echo "🔧 修复问题后重新推送:"
  echo "   git push"
  echo ""
  echo "⚡ 或跳过部署直接推送(不推荐):"
  echo "   git push --no-verify"
  echo ""
  exit 1
fi

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ 部署成功,继续push"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

exit 0

作用

  • 在推送前询问是否部署
  • 执行自动化部署脚本
  • 部署失败时阻止 push,确保 Git 和服务器同步
  • 只对 main 分支生效

关键设计

  1. 部署失败阻止 push:确保代码和线上环境始终一致
  2. 可选择跳过:不想部署时可以选择只 push
  3. 分支过滤:只对 main 分支触发部署
  4. 详细提示:失败时给出明确的处理建议

权限设置

确保 hook 文件具有执行权限:

bash
chmod +x .husky/pre-commit .husky/commit-msg .husky/pre-push

Package.json 脚本配置

package.json 中添加常用脚本:

json
{
  "scripts": {
    "prepare": "husky",
    "lint": "eslint . --ext .js,.ts,.vue",
    "lint:fix": "eslint . --ext .js,.ts,.vue --fix",
    "format": "prettier --write \"**/*.{js,ts,vue,md,json}\"",
    "deploy": "./scripts/deploy.sh",
    "deploy:status": "cat ~/.deploy-status/blog.json",
    "deploy:logs": "cat ~/.deploy-logs/blog-latest.log"
  }
}

工作流程

CI 阶段(Commit)

  1. 开发者执行 git add: 将文件添加到暂存区
  2. 开发者执行 git commit: 触发 pre-commit hook
  3. Pre-commit 执行:
    • 运行 lint-staged
    • 对暂存文件执行 Prettier 格式化
    • 对暂存文件执行 ESLint 检查和自动修复
    • 如果有错误,提交被阻止
  4. Commit-msg 执行:
    • 验证提交信息格式
    • 确保符合 Conventional Commits 规范
  5. 提交成功: 所有检查通过后,提交完成

CD 阶段(Push)

  1. 开发者执行 git push: 触发 pre-push hook
  2. Pre-push 执行:
    • 检查当前分支(只对 main 分支生效)
    • 询问是否部署
    • 如果选择部署,执行部署脚本
    • 部署失败则阻止 push
  3. Push 成功: 部署成功后,代码推送到远程仓库

完整流程图

开发阶段

git add .

git commit -m "feat: xxx"

┌─────────────────────────────────────────┐
│  CI (持续集成) - commit 阶段              │
├─────────────────────────────────────────┤
│  pre-commit:                            │
│    ✓ lint-staged (暂存文件检查)           │
│    ✓ ESLint (代码检查)                   │
│    ✓ Prettier (代码格式化)               │
│                                         │
│  commit-msg:                            │
│    ✓ Commitlint (提交信息规范检查)         │
└─────────────────────────────────────────┘

提交成功

git push

┌─────────────────────────────────────────┐
│  CD (持续部署) - push 阶段               │
├─────────────────────────────────────────┤
│  pre-push:                              │
│    1. 询问是否部署                       │
│    2. 本地构建(Docker 容器内)          │
│    3. 检查 SSH 连接                      │
│    4. 服务器端备份                       │
│    5. Rsync 同步到服务器                 │
│    6. 服务器重启容器                     │
│    7. 健康检查                           │
└─────────────────────────────────────────┘

部署成功 + push 成功 ✅

提交信息规范

遵循 Conventional Commits 规范:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

示例

feat(auth): add user login functionality

Implement JWT-based authentication with login form validation
and error handling for invalid credentials.

Closes #123

配置详解

ESLint 配置(ESM 项目)

Blog 项目使用 ESM("type": "module"),需要使用 eslint.config.mjs

javascript
import js from '@eslint/js'
import globals from 'globals'
import vue from 'eslint-plugin-vue'
import prettier from 'eslint-plugin-prettier'
import tseslint from 'typescript-eslint'

export default [
  js.configs.recommended,
  ...tseslint.configs.recommended,
  ...vue.configs['flat/recommended'],
  {
    plugins: {
      prettier
    },
    languageOptions: {
      globals: {
        ...globals.browser,
        ...globals.node
      }
    },
    rules: {
      'prettier/prettier': 'error',
      '@typescript-eslint/no-explicit-any': 'warn',
      'vue/multi-word-component-names': 'off'
    }
  },
  {
    ignores: ['node_modules', 'dist', '.vitepress/dist', '.vitepress/cache']
  }
]

关键点

  • 使用 Flat Config 格式(ESLint 9+)
  • 集成 Prettier 作为 ESLint 规则
  • 配置 Vue 3 支持
  • 忽略构建产物和缓存目录

Lint-staged 工作方式

  • 文件过滤: 只对暂存区中匹配模式的文件执行操作
  • 并行执行: 同时运行多个工具提高效率
  • 自动修复: Prettier 和 ESLint 会自动修复可修复的问题
  • 失败处理: 如果有无法自动修复的问题,会阻止提交

使用场景示例

场景1:正常开发流程

bash
# 1. 开发完成
git add .
git commit -m "feat: 添加新功能"
# ✓ 自动执行 lint 和格式化
# ✓ 自动检查提交信息

# 2. 推送并部署
git push
# 提示:是否部署?(y/n)
# 输入:y
# ✓ 自动构建
# ✓ 自动同步
# ✓ 自动部署
# ✓ 自动验证

# 3. 完成
# Git 和服务器都是最新版本 ✅

场景2:部署失败处理

bash
# 推送时部署失败
git push
# ❌ 部署失败,push 已终止

# 查看失败原因
pnpm run deploy:logs

# 修复问题
git add .
git commit -m "fix: 修复部署问题"

# 重新推送
git push
# ✅ 部署成功

场景3:跳过部署

bash
# 只想推送代码,不部署
git push
# 提示:是否部署?(y/n)
# 输入:n
# ⏸️ 跳过部署,继续 push

# 稍后手动部署
pnpm run deploy

跳过 Hook 检查

在紧急情况下可以跳过 hooks:

bash
# 跳过所有 hooks(包括部署)
git push --no-verify

# 跳过 pre-commit hook
git commit --no-verify -m "emergency fix"

注意:

  • 仅在紧急情况下使用
  • 跳过部署后必须稍后手动部署:pnpm run deploy
  • 禁止常规使用,会破坏代码质量和部署一致性

总结

自动化实践方面

Husky 主要体现在以下自动化功能:

  1. 自动代码检查 :在 pre-commit 钩子中自动运行 ESLint 和 Prettier
  2. 自动提交信息验证 :在 commit-msg 钩子中自动检查提交信息格式
  3. 自动化流程触发 :无需手动执行,Git 操作时自动触发相应检查
  4. 自动阻止不合规操作 :检查失败时自动阻止提交或推送

工程化实践方面

Husky 配置也是重要的工程化实践:

  1. 开发规范标准化 :统一团队的代码风格和提交规范
  2. 质量保障体系 :建立代码质量检查的工程化流程
  3. 团队协作规范 :确保所有开发者遵循相同的开发标准
  4. 项目配置管理 :通过配置文件管理项目的质量控制策略

综合定位

Husky 更准确地说是「工程化驱动的自动化实践」 :

  • 工程化思维 :从项目整体质量和团队协作角度设计规范
  • 自动化手段 :通过技术手段自动执行这些工程化规范
  • 系统性解决方案 :不仅仅是单个工具,而是完整的质量保障体系

在项目中的价值

  1. 提升开发效率 :减少人工检查,自动发现问题
  2. 保证代码质量 :统一代码风格,减少低级错误
  3. 规范团队协作 :标准化的提交信息便于项目管理
  4. 降低维护成本 :早期发现问题,减少后期修复成本

因此,Husky 是现代前端工程化体系中不可或缺的一环,它通过自动化手段实现了工程化的质量管控目标。

Released under the MIT License.