大家好,我是农村程序员,独立开发者,行业观察员,VSCode 插件批发商,前端之虎陈随易。
我会在这里分享关于 独立开发
、编程技术
、思考感悟
等内容,欢迎关注。
- 网站 1️⃣:chensuiyi.me
- 网站 2️⃣:me.yicode.tech
技术群与交朋友请在个人网站 👆 联系我,如果你觉得本文有用,一键三连 (点赞
、评论
、转发
),就是对我最大的支持~
在前端项目中,代码格式化是保证代码质量和团队协作的重要环节。
很多团队使用 husky
+ lint-staged
来实现 Git 提交前的自动格式化,但这种方案需要安装额外的依赖,增加了项目的复杂度。
本文将介绍如何直接使用 Git 原生的 Hooks 机制,不依赖任何第三方库,实现同样的功能。
为什么不用 Husky?
传统方案的问题
使用 husky
+ lint-staged
的典型配置:
json
{
"devDependencies": {
"husky": "^9.0.0",
"lint-staged": "^15.0.0",
"prettier": "^3.0.0"
},
"scripts": {
"prepare": "husky install"
},
"lint-staged": {
"*.{js,ts,jsx,tsx}": "prettier --write"
}
}
缺点:
- 需要安装多个依赖包(husky、lint-staged)
- 需要额外的配置文件(.husky 目录)
- 团队成员克隆项目后需要运行
npm install
才能启用 hooks - 依赖包的版本更新可能带来兼容性问题
原生方案的优势
直接使用 Git Hooks:
- ✅ 零依赖 - 只需要 prettier(或其他格式化工具)
- ✅ 简单直接 - 一个 shell 脚本文件即可
- ✅ 性能更好 - 没有额外的 Node.js 进程启动开销
- ✅ 完全控制 - 可以自定义任何逻辑
Git Hooks 基础知识
什么是 Git Hooks?
Git Hooks 是 Git 在特定事件(如提交、推送等)发生时自动执行的脚本。这些脚本存放在项目的 .git/hooks/
目录下。
常用的 Hooks:
pre-commit
- 提交前执行(本文重点)commit-msg
- 提交信息验证pre-push
- 推送前执行post-merge
- 合并后执行
为什么 .git/hooks/ 不在版本控制中?
.git/
目录默认不被 Git 跟踪,所以 .git/hooks/
中的脚本无法通过 Git 共享给团队成员。
这也是 husky 存在的主要原因之一 - 它通过在 package.json
中配置,让团队成员在 npm install
时自动设置 hooks。
如何分享 Git Hooks?
有几种方法:
- 文档说明 - 在 README 中说明如何手动复制脚本
- 初始化脚本 - 提供一个设置脚本,团队成员运行一次即可
- Git 2.9+ 的 core.hooksPath - 将 hooks 目录设置为可追踪的路径
实现方案
直接修改 .git/hooks/pre-commit
创建 pre-commit 脚本
在 .git/hooks/pre-commit
文件中写入以下内容:
bash
#!/usr/bin/env sh
# Git pre-commit hook - 自动格式化暂存的文件
echo "正在检查暂存文件..."
# 获取所有暂存的文件(只包括添加和修改的文件)
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx|vue|json|md|yaml|yml|css|scss|less|html)$')
if [ -z "$STAGED_FILES" ]; then
echo "没有需要格式化的文件"
exit 0
fi
echo "正在格式化以下文件:"
echo "$STAGED_FILES"
# 将文件列表转换为数组并逐个格式化
echo "$STAGED_FILES" | while IFS= read -r file; do
if [ -f "$file" ]; then
bunx prettier --write "$file"
git add "$file"
fi
done
echo "✓ 代码格式化完成"
exit 0
安装 Prettier
只需要一个依赖:
bash
npm install -D prettier
# 或
bun add -d prettier
测试
创建一个格式不规范的测试文件:
javascript
// test.js
const obj = { a: 1, b: 2, c: 3 };
const fn = (x, y) => {
return x + y;
};
console.log(obj);
提交文件:
bash
git add test.js
git commit -m "测试自动格式化"
Hook 会自动运行,输出类似:
csharp
正在检查暂存文件...
正在格式化以下文件:
test.js
test.js 24ms
✓ 代码格式化完成
[main abc1234] 测试自动格式化
1 file changed, 3 insertions(+)
查看格式化后的文件:
javascript
// test.js - 已格式化
const obj = { a: 1, b: 2, c: 3 };
const fn = (x, y) => {
return x + y;
};
console.log(obj);
高级用法
支持多种格式化工具
bash
#!/usr/bin/env sh
echo "正在格式化代码..."
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
# JavaScript/TypeScript 文件使用 Prettier
JS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(js|ts|jsx|tsx)$')
if [ -n "$JS_FILES" ]; then
echo "$JS_FILES" | xargs bunx prettier --write
echo "$JS_FILES" | xargs git add
fi
# CSS/SCSS 文件使用 stylelint
CSS_FILES=$(echo "$STAGED_FILES" | grep -E '\.(css|scss)$')
if [ -n "$CSS_FILES" ]; then
echo "$CSS_FILES" | xargs bunx stylelint --fix
echo "$CSS_FILES" | xargs git add
fi
# Python 文件使用 black
PY_FILES=$(echo "$STAGED_FILES" | grep -E '\.py$')
if [ -n "$PY_FILES" ]; then
echo "$PY_FILES" | xargs black
echo "$PY_FILES" | xargs git add
fi
echo "✓ 格式化完成"
exit 0
添加 ESLint 检查
bash
#!/usr/bin/env sh
echo "正在检查代码..."
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx)$')
if [ -z "$STAGED_FILES" ]; then
exit 0
fi
# 先格式化
echo "$STAGED_FILES" | xargs bunx prettier --write
echo "$STAGED_FILES" | xargs git add
# 再进行 ESLint 检查
echo "运行 ESLint..."
echo "$STAGED_FILES" | xargs bunx eslint
# 如果 ESLint 失败,阻止提交
if [ $? -ne 0 ]; then
echo "❌ ESLint 检查失败,请修复错误后再提交"
exit 1
fi
echo "✓ 检查通过"
exit 0
只格式化改动的部分(增量格式化)
对于大型项目,可以使用 prettier
的 --check
选项先检查,只格式化需要修改的文件:
bash
#!/usr/bin/env sh
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|ts|jsx|tsx)$')
if [ -z "$STAGED_FILES" ]; then
exit 0
fi
echo "检查文件格式..."
# 先检查哪些文件需要格式化
NEED_FORMAT=$(echo "$STAGED_FILES" | xargs bunx prettier --list-different)
if [ -n "$NEED_FORMAT" ]; then
echo "正在格式化以下文件:"
echo "$NEED_FORMAT"
# 只格式化需要的文件
echo "$NEED_FORMAT" | xargs bunx prettier --write
echo "$NEED_FORMAT" | xargs git add
echo "✓ 格式化完成"
else
echo "所有文件格式正确,无需格式化"
fi
exit 0
性能对比
Husky + Lint-staged
bash
# 启动时间
$ time git commit -m "test"
real 0m2.341s # 包括 Node.js 启动、lint-staged 初始化等
user 0m1.234s
sys 0m0.567s
原生 Git Hooks
bash
# 启动时间
$ time git commit -m "test"
real 0m0.482s # 仅 shell 脚本 + prettier 执行
user 0m0.123s
sys 0m0.089s
性能提升约 4-5 倍!
总结
何时使用原生 Git Hooks?
✅ 适合的场景:
- 小型团队或个人项目
- 追求最小依赖和简洁配置
- 对性能有要求的项目
- 团队成员都熟悉 Git Hooks
❌ 不适合的场景:
- 需要复杂的 hook 管理(多个 hooks,条件执行等)
- 团队成员对 Git Hooks 不熟悉
- 需要跨平台的复杂逻辑
何时使用 Husky?
✅ 适合的场景:
- 大型团队项目
- 需要管理多个 Git Hooks
- 团队成员水平参差不齐
- 需要开箱即用的解决方案
最终建议
对于大多数项目,我推荐:
- 开发阶段 - 使用原生 Git Hooks(简单、快速)
- 生产项目 - 如果团队较大,可以考虑 Husky(更容易管理)
- 两者结合 - 保留原生 hooks 的简洁性,通过文档和脚本帮助团队成员设置
希望这篇文章能帮助你摆脱对第三方 hooks 库的依赖,用最简单的方式实现代码自动格式化!
🔥 我的 VSCode 扩展商店:
👉 点击访问
