Husky 配置指南
本文档详细介绍了在 Blog 项目中配置 Husky 的完整过程,包括代码质量检查、提交信息规范、自动化部署等最佳实践。
本指南基于 Blog 项目的实际落地经验总结,适用于 VitePress 静态站点项目。
什么是 Git Hooks
Git hooks 是在 Git 执行特定操作时自动运行的脚本。常用的 hooks 包括:
pre-commit: 在提交前执行,用于代码检查和格式化commit-msg: 在提交信息创建后执行,用于验证提交信息格式pre-push: 在推送前执行,用于最终检查和自动化部署
Husky
Husky 是一个 Git hooks 工具,它可以让你在 Git 操作的特定时机自动执行脚本。
主要优势
- 代码质量保证: 在代码提交前自动执行 ESLint、Prettier 等工具
- 提交规范: 强制执行 Conventional Commits 规范
- 团队协作: 确保所有团队成员遵循相同的代码标准
- 自动化: 减少手动检查,提高开发效率
- 错误预防: 在代码进入仓库前发现并修复问题
使用场景
- 多人协作项目: 确保代码风格一致性
- 持续集成/持续部署: 在提交代码前进行自动化检查和部署
- 代码审查: 提高 PR 质量,减少审查时间
- 规范化开发: 建立标准化的开发流程
- 自动化部署: 结合 pre-push hook 实现推送即部署
实现过程
1. 安装依赖
首先安装必要的开发依赖:
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
pnpm exec husky init这个命令会:
- 创建
.husky目录 - 生成基础的 hook 文件
- 在
package.json中添加prepare脚本:"prepare": "husky"
3. 配置文件创建
3.1 创建 Commitlint 配置
创建 commitlint.config.cjs(如果项目是 ESM,建议使用 .cjs 后缀):
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:
module.exports = {
singleQuote: true, // 使用单引号
trailingComma: 'all', // 尾随逗号
printWidth: 100, // 每行最大长度
semi: true, // 使用分号
tabWidth: 2, // 缩进宽度
endOfLine: 'lf', // 换行符(Unix)
arrowParens: 'always' // 箭头函数参数括号
}3.3 Lint-staged 配置
在 package.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/cacheHook 脚本配置
4.1 Pre-commit Hook
创建 .husky/pre-commit:
npx lint-staged作用:在提交前对暂存的文件执行 Prettier 格式化和 ESLint 检查
4.2 Commit-msg Hook
创建 .husky/commit-msg:
npx --no -- commitlint --edit $1作用:验证提交信息是否符合 Conventional Commits 规范
4.3 Pre-push Hook(可选,用于自动化部署)
创建 .husky/pre-push:
#!/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 分支生效
关键设计:
- 部署失败阻止 push:确保代码和线上环境始终一致
- 可选择跳过:不想部署时可以选择只 push
- 分支过滤:只对 main 分支触发部署
- 详细提示:失败时给出明确的处理建议
权限设置
确保 hook 文件具有执行权限:
chmod +x .husky/pre-commit .husky/commit-msg .husky/pre-pushPackage.json 脚本配置
在 package.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)
- 开发者执行
git add: 将文件添加到暂存区 - 开发者执行
git commit: 触发 pre-commit hook - Pre-commit 执行:
- 运行
lint-staged - 对暂存文件执行 Prettier 格式化
- 对暂存文件执行 ESLint 检查和自动修复
- 如果有错误,提交被阻止
- 运行
- Commit-msg 执行:
- 验证提交信息格式
- 确保符合 Conventional Commits 规范
- 提交成功: 所有检查通过后,提交完成
CD 阶段(Push)
- 开发者执行
git push: 触发 pre-push hook - Pre-push 执行:
- 检查当前分支(只对 main 分支生效)
- 询问是否部署
- 如果选择部署,执行部署脚本
- 部署失败则阻止 push
- 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:
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:正常开发流程
# 1. 开发完成
git add .
git commit -m "feat: 添加新功能"
# ✓ 自动执行 lint 和格式化
# ✓ 自动检查提交信息
# 2. 推送并部署
git push
# 提示:是否部署?(y/n)
# 输入:y
# ✓ 自动构建
# ✓ 自动同步
# ✓ 自动部署
# ✓ 自动验证
# 3. 完成
# Git 和服务器都是最新版本 ✅场景2:部署失败处理
# 推送时部署失败
git push
# ❌ 部署失败,push 已终止
# 查看失败原因
pnpm run deploy:logs
# 修复问题
git add .
git commit -m "fix: 修复部署问题"
# 重新推送
git push
# ✅ 部署成功场景3:跳过部署
# 只想推送代码,不部署
git push
# 提示:是否部署?(y/n)
# 输入:n
# ⏸️ 跳过部署,继续 push
# 稍后手动部署
pnpm run deploy跳过 Hook 检查
在紧急情况下可以跳过 hooks:
# 跳过所有 hooks(包括部署)
git push --no-verify
# 跳过 pre-commit hook
git commit --no-verify -m "emergency fix"注意:
- 仅在紧急情况下使用
- 跳过部署后必须稍后手动部署:
pnpm run deploy - 禁止常规使用,会破坏代码质量和部署一致性
总结
自动化实践方面
Husky 主要体现在以下自动化功能:
- 自动代码检查 :在 pre-commit 钩子中自动运行 ESLint 和 Prettier
- 自动提交信息验证 :在 commit-msg 钩子中自动检查提交信息格式
- 自动化流程触发 :无需手动执行,Git 操作时自动触发相应检查
- 自动阻止不合规操作 :检查失败时自动阻止提交或推送
工程化实践方面
Husky 配置也是重要的工程化实践:
- 开发规范标准化 :统一团队的代码风格和提交规范
- 质量保障体系 :建立代码质量检查的工程化流程
- 团队协作规范 :确保所有开发者遵循相同的开发标准
- 项目配置管理 :通过配置文件管理项目的质量控制策略
综合定位
Husky 更准确地说是「工程化驱动的自动化实践」 :
- 工程化思维 :从项目整体质量和团队协作角度设计规范
- 自动化手段 :通过技术手段自动执行这些工程化规范
- 系统性解决方案 :不仅仅是单个工具,而是完整的质量保障体系
在项目中的价值
- 提升开发效率 :减少人工检查,自动发现问题
- 保证代码质量 :统一代码风格,减少低级错误
- 规范团队协作 :标准化的提交信息便于项目管理
- 降低维护成本 :早期发现问题,减少后期修复成本
因此,Husky 是现代前端工程化体系中不可或缺的一环,它通过自动化手段实现了工程化的质量管控目标。