使用Git钩子+ husky + lint语法检查提高前端项目代码质量

news/2025/11/6 19:34:02/文章来源:https://www.cnblogs.com/jevonsflash/p/19197576

@

目录
  • 配置 Git Hook
    • 原理介绍
    • 安装 Husky
    • 启用 Husky
    • 添加 Git Hook
    • 测试脚本
    • 执行效果
  • 添加语法检查
    • 安装Prettier
    • 配置Prettier
    • 格式化规则调优
    • 添加 Git Hook
  • 添加Git提交规范检查
    • 安装commitlint
    • 配置commitlint
    • 添加 Git Hook

作为开发经理,是不是常常有一个疑问:怎样保证项目代码质量和可维护性?今天我将通过几个我在团队中常用的工具,提高代码质量,降低隐性的故障率与积累的维护成本,避免“技术债”。

首先,要保证代码仓库每次提交的代码质量,需要在提交前引入检查机制,可以使用 Git hooks。在提交前运行各检查,如果检查不通过,就阻止提交。

本地 Git Hook 默认不会随仓库共享,所以如果只放在 .git/hooks/pre-commit 里,其他人 clone 下来是没有这个 hook 的。

团队里常用的办法是借助 Husky,把钩子配置放在项目里,随代码共享。

当然,由于是在本地,组员可以通过跳过 Git 钩子的方式绕过代码检查,最权威的方案还是在 GitLab 服务端强制检查:用 GitLab CI/CD pipeline 配置,在 pipeline 阶段执行 tsc,不通过则拒绝 merge request。本篇文章只讨论本地 Git Hook 的做法。以后有机会再介绍服务端检查。

配置 Git Hook

原理介绍

.git/hooks 目录不会随着代码被提交,所以要用第三方库,Husky 是用 Git 自带的 hook 原理,只是做了几件事:

  • Git 在 .git/hooks/ 目录下放置一堆钩子脚本(例如 pre-commitpre-pushcommit-msg)。

  • 当执行 git commitgit push 等操作时,Git 会去 .git/hooks/ 找对应的脚本并执行。

  • 如果脚本返回非零退出码(exit 1),Git 会中止操作。

安装 Husky

运行如下命令:

yarn add husky --dev

启用 Husky

运行如下命令:

yarn husky install

此时项目会有 .husky/ 目录,里面放着 Git Hook 脚本。

为了保证每次别人 yarn install 时 Husky 自动启用,需要在 package.json 里加一个 postinstall 脚本:

{"scripts": {"postinstall": "husky install","type-check": "tsc --noEmit"}
}

当组员提交代码时,会执行如下的流程:

  1. Husky 会在 .git/hooks/ 目录写入一个 代理脚本。

  2. 代理脚本会去执行 .husky/ 目录下的对应 hook 文件,比如 .husky/pre-commit

  3. .husky/pre-commit 里通常就写需要的命令,比如 npm run lint && npm run type-check

  4. 如果命令失败(退出码非 0),Git 就会阻止 commit。

添加 Git Hook

在项目根目录的 .husky/ 创建 pre-commit 文件:

在这里插入图片描述

将如下内容写入文件:

#!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh"echo "🔍 Running type check before commit..."# 运行 TS 检查
yarn type-check
RESULT=$?if [ $RESULT -ne 0 ]; thenecho "❌ Type check failed. Commit aborted."exit 1
fiecho "✅ Type check passed. Proceeding with commit."
exit 0

测试脚本

保证脚本编码和换行符符合规范:

在这里插入图片描述

在Windows下,git是通过Windows Git Bash 环境里执行 hook, 不是命令行环境也不是Powershell!

使用Windows Git Bash,运行sh .husky/pre-commit,查看打印:

在这里插入图片描述

能打印出脚本的输出,说明脚本执行正常。

执行效果

  • 当执行 git commit 时,Husky 会先跑 yarn type-check

  • 如果 tsc 报错(退出码非 0),commit 会被阻止。

简单来说:Husky = Git hook 的自动安装器 + 管理器

添加语法检查

除了提交前运行 tsc 检查,防止硬性语法错误以外,代码格式统一和规范性检测,也是 Git Hook 其中一个任务。

这里使用 ESLint + TypeScript ESLint + Prettier 组合来统一代码规范与格式

安装Prettier

在项目根目录下执行:

yarn add -D @typescript-eslint/parser @typescript-eslint/eslint-plugin
yarn add -D prettier eslint-config-prettier eslint-plugin-prettier

配置Prettier

在项目根目录下创建 eslint.config.js

完整的配置

// @ts-checkimport eslint from "@eslint/js";
import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended";
import unusedImports from "eslint-plugin-unused-imports";
import { defineConfig } from "eslint/config";
import tseslint from "typescript-eslint";export default defineConfig(eslint.configs.recommended,tseslint.configs.recommended,eslintPluginPrettierRecommended,{plugins: {"unused-imports": unusedImports},files: ["*.js", "src/**/*.{js,jsx,mjs,cjs,ts,tsx}"],ignores: ["dist/**/*.*", "node_modules/**/*.*"],languageOptions: {parserOptions: {projectService: true,// eslint-disable-next-line @typescript-eslint/ban-ts-comment// @ts-expect-errortsconfigRootDir: import.meta.dirname}},rules: {"max-len": "off","object-curly-spacing": "off","@typescript-eslint/no-explicit-any": "off","@typescript-eslint/no-unused-vars": "off","@typescript-eslint/no-unsafe-function-type": "off","@typescript-eslint/no-this-alias": "off","@typescript-eslint/no-unused-expressions": "off","no-var": "off","prefer-const": "off","no-empty": "off","unused-imports/no-unused-imports": "error","unused-imports/no-unused-vars": ["warn",{vars: "all",varsIgnorePattern: "^_",args: "after-used",argsIgnorePattern: "^_"}],quotes: "off","prettier/prettier": ["warn",{semi: true,singleQuote: false,trailingComma: "none",printWidth: 180,tabWidth: 2,useTabs: false,bracketSpacing: true,arrowParens: "avoid",endOfLine: "auto"}]}}
);

格式化规则调优

每个团队对于代码规范有自己的理解,不同的团队有不同的格式化规则,请根据你的实际情况来调整。

我的代码规范遵循如下原则:

  1. 兼顾可读性与灵活性:某些严格规则被关闭,只保留关键检查。具体配置如下
规则 说明
"max-len": "off" 不限制每行最大长度
"object-curly-spacing": "off" 不强制对象花括号的空格风格
"@typescript-eslint/no-explicit-any": "off" 允许使用 any 类型
"@typescript-eslint/no-unused-vars": "off" 改用 unused-imports 插件来检测未使用变量
"@typescript-eslint/no-unsafe-function-type": "off" 允许函数类型较宽松
"@typescript-eslint/no-this-alias": "off" 允许使用 const self = this 等别名方式
"@typescript-eslint/no-unused-expressions": "off" 允许未被使用的表达式(如短路逻辑)
"no-var": "off" 允许使用 var
"prefer-const": "off" 不强制将变量声明为 const
"no-empty": "off" 允许空代码块
"quotes": "off" 不强制单双引号风格
  1. 注重重用:关注未使用 import / 变量、代码格式一致性。

额外启用了 “eslint-plugin-unused-imports” 插件,专门用于检测未使用的 import 与变量,配置如下

"unused-imports/no-unused-imports": "error",
"unused-imports/no-unused-vars": ["warn",{vars: "all",varsIgnorePattern: "^_",args: "after-used",argsIgnorePattern: "^_"}
]

使用 Prettier 实现 IDE 和 ESLint 一体化:格式规则通过 Prettier 统一控制,避免 ESLint 规则重复,同时避免 VS Code 格式化工具与 ESLint 产生冲突。

选项 含义
semi true 语句末尾加分号
singleQuote false 使用双引号
trailingComma "none" 不使用尾随逗号
printWidth 180 每行最大宽度 180
tabWidth 2 每个缩进为 2 个空格
useTabs false 使用空格而非 Tab
bracketSpacing true 对象花括号内保留空格
arrowParens "avoid" 箭头函数参数单个时省略括号
endOfLine "auto" 自动适配操作系统换行符
报告级别 "warn" 仅提示警告,不阻止构建

所有 JS/TS/React/JSON 文件均采用 Prettier 作为唯一格式化器,与 ESLint 中的 Prettier 配置保持一致:

在这里插入图片描述

在开发组成员的VSCode中,安装esbenp插件,并配置如下:

在`/.vscode/settings.json中添加如下配置,并且将文件提交到项目仓库

"[javascript]": {"editor.insertSpaces": true,"editor.defaultFormatter": "esbenp.prettier-vscode"},"[typescript]": {"editor.insertSpaces": true,"editor.defaultFormatter": "esbenp.prettier-vscode"},"[typescriptreact]": {"editor.insertSpaces": true,"editor.defaultFormatter": "esbenp.prettier-vscode"},"[json]": {"editor.defaultFormatter": "esbenp.prettier-vscode"},

同时建议开启自动保存

"editor.formatOnSave": true, 
"editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit", "source.fixAll.stylelint": "explicit" },

在项目根目录下创建.prettierrc.js文件,内容如下:

export default {semi: true,singleQuote: false,trailingComma: "none",printWidth: 180,tabWidth: 2,useTabs: false,bracketSpacing: true,arrowParens: "avoid",endOfLine: "auto"
};

如此,当代VS Code中码文件保存,将自动执行与Eslint规则一致的自动格式化。

添加 Git Hook

package.json 里,添加lint相关脚本

{"scripts": {..."lint": "eslint src/**/*.{ts,tsx}","lint:fix": "eslint src/**/*.{ts,tsx} --fix",}
}

修改项目根目录的 .husky/pre-commit 文件,在之前的基础上,添加“Running ESLint check”:

#!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh"echo "🔍 Running TypeScript type check..."
yarn type-check
TYPE_RESULT=$?echo "🔍 Running ESLint check..."
yarn lint
LINT_RESULT=$?if [ $TYPE_RESULT -ne 0 ] || [ $LINT_RESULT -ne 0 ]; thenecho "❌ Commit aborted due to type or lint errors."exit 1
fiecho "✅ All checks passed. Proceeding with commit."
exit 0

添加Git提交规范检查

为了保证代码提交历史清晰可读、便于回溯和自动化工具处理,我们统一使用 Conventional Commits 规范

安装commitlint

yarn add -D @commitlint/config-conventional @commitlint/cli

配置commitlint

制定的规则如下:

  • 类型 - 用于描述本次提交的类别,必须从以下列表中选择:
类型 说明
feat 新功能(feature)
fix 修复 bug
docs 文档修改
style 代码格式修改(不影响功能,如空格、分号、缩进等)
refactor 重构代码(既不新增功能,也不是修复 bug)
perf 性能优化
test 测试相关修改(新增或修改已有测试)
revert 回滚 commit
build 构建流程、依赖变更(如升级 npm 包、修改打包配置)
ci CI 配置或脚本修改
types 类型定义文件修改(如 TypeScript 类型文件)
  • 可选范围 - 用于描述本次提交影响的模块或范围,例如 buttonapilogin 等,非必填:
    feat(login): 增加登录验证码功能

  • 主题 - 简明扼要描述本次提交做了什么,不做大小写限制fix(api): 修复获取用户信息接口报错 docs: 更新 README 文档说明

  • 正文 - 正文为对提交的详细描述,可以分行书写,要求正文前空一行,可用于说明实现思路、原因、可能影响等:

feat(payment): 添加支付宝支付功能- 支持扫码支付
- 支持手机端支付
- 更新支付相关文档
  • 脚注 - 用于关联 issue 或记录 BREAKING CHANGE:BREAKING CHANGE: 接口返回字段 userId 修改为 uid Closes #123

在项目根目录下创建 .commitlintrc.json 文件,内容如下:

export default {// 继承的规则extends: ["@commitlint/config-conventional"],// 定义规则类型rules: {"body-leading-blank": [2, "always"], // 确保提交消息正文之前有一行空白行"type-empty": [2, "never"], // 不允许提交消息的 type 类型为空"subject-case": [0], // subject 大小写不做校验// type 类型定义,表示 git 提交的 type 必须在以下类型范围内"type-enum": [2,"always",["feat", // 新功能 feature"fix", // 修复 bug"docs", // 文档注释"style", // 代码格式(不影响代码运行的变动)"refactor", // 重构(既不增加新功能,也不是修复bug)"perf", // 性能优化"test", // 添加疏漏测试或已有测试改动"revert", // 回滚commit"build", // 构建流程、外部依赖变更 (如升级 npm 包、修改打包配置等)',"ci", // 修改CI配置、脚本"types" // 类型定义文件修改]]}
};

添加 Git Hook

package.json 里,添加commitlint脚本:

{"scripts": {..."commitlint": "commitlint --config commitlint.config.js --edit"}
}

在项目根目的 .husky/ 目录中创建 commit-msg 文件,内容如下:

#!/usr/bin/env sh
. "$(dirname "$0")/_/husky.sh"echo "🔍 Running commitlint check..."
yarn commitlint
RESULT=$?if [ $RESULT -ne 0 ] ; thenecho "❌ Commit aborted due to commitlint errors."exit 1
fiecho "✅ All checks passed. Proceeding with commit."
exit 0

至此,我们就完成了前端项目的代码质量检查工具的搭建。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/958043.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[题解]P10277 [USACO24OPEN] Bessies Interview S

P10277 [USACO24OPEN] Bessies Interview S 第一问可以用优先队列模拟,存储每个人的结束时间即可。 第二问,一开始考虑的是对于某一时刻队列中结束时间最小的人是可以任意互换顺序的,所以就用并查集把这些人合在一起…

关于 Java快速查找详细

package V_Recursion;public class C_QuickSort {public static void main(String[] args) {int[] arr = {6, 1, 2, 7, 9, 3, 4, 5, 10, 8};quicSort(arr, 0, arr.length - 1);for (int i = 0; i < arr.length; i++…

什么是Ansible 清单 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

完整教程:如何用开源软件

完整教程:如何用开源软件pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &…

第一次团队项目作业

软件工程团队项目第一次作业 - VALORANT 智能战术助手(第一部分) 作业信息这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/202501SoftwareEngineering/这个作业要求在哪里 https://edu.cnblogs.com/campu…

隨機變量本質之最終闡述

懷特博士: 我的理智所剩無幾,必須儘快警告您——切勿觸碰概率的本質!那个不可名狀的存在堂而皇之地通過霍爾教授的死宣誓著自己的主宰。Kl-mghrov——我無法準確發音,這個名字本身就讓燈光閃爍、指針顫動。我是如此…

足式机器人适应多地形的方案

基于视觉的感知运动 两阶段方法:流程:首先在完全可观测的马尔可夫决策过程(MDP) 中,利用特权信息训练一个强大的教师策略。然后,通过知识蒸馏,将教师策略的知识迁移给一个仅能使用真实传感器数据的学生策略。优…

使用vLLM实测3090和4090的大模型推理性能

使用`vLLM`测试下大模型并发推理场景下3090和4090两张显卡的性能表现,看下4090是否在高并发场景下具备更高的扩展性。 3090显卡和4090显卡在模型推理过程中的显存和GPU使用率都比较接近,1~8并发度场景下,3090和409…

CF1700F Puzzle

考虑如果是 \(1 \times n\) 怎么做。 显然是前缀和的差的绝对值的和,因为每次移动改变一位前缀和。 考虑上下交换的本质是什么,就是给第一行减 \(1\),第二行加 \(1\),反过来同理,那么在前缀和异号时显然交换是不劣…

Redis高可用与高并发探险之旅:从单机到集群的完美进化【第三部分】

可以结合之前的文章融合起来一起理解学习:分布式缓存-Redis集群在一个名为"数据大陆"的世界里,Redis王国正面临着前所未有的挑战。随着用户流量的激增,单机Redis服务器已经不堪重负。今天,就让我们跟随年…

UE:论运行时动画录制的关键-正确获取骨骼数据与保存

© mengzhishanghun 原创文章 首发于 博客园 禁止未经授权转载核心问题 在 UE5.4 中实现运行时动画录制,最关键的两个问题是:如何获取正确的骨骼数据 - 避免崩溃和数据不匹配如何正确保存 AnimSequence - 使用…

a-menu 当设置折叠状态如何穿透悬浮菜单样式

效果antReset.css .ant-menu-submenu .ant-menu-submenu-popup .ant-menu .ant-menu-light {border: 1px solid #173808 !important; }/* 直接针对 popup 整体背景 */ .ant-menu-submenu-popup {background-color: #17…

attention论文及Transformer工作原理概述

attention论文及Transformer工作原理概述Posted on 2025-11-06 19:09 wsg_blog 阅读(0) 评论(0) 收藏 举报attention论文及Transformer工作原理概述

kamailio+rtpengine对sdp的处理

概述 使用kamailio+rtpengine的过程中,默认会使用rtpengine处理sdp信息,同时又需要对sdp信息定制,就需要对cfg配置流程中做特殊处理才能实现。 环境 CentOS 7.9 kamailio:5.8.3-bullseye docker rtpengine:mr13.1.1…

软工团队项目第一次作业

软工团队项目第一次作业作业所属课程 https://edu.cnblogs.com/campus/fzu/202501SoftwareEngineering/作业要求 https://edu.cnblogs.com/campus/fzu/202501SoftwareEngineering/homework/13573作业的目标 团队展示+选…

低代码权限管理安全合规指南:守住数据安全的 “最后一道防线”

随着数据安全法、个人信息保护法的落地,企业对系统权限管理的合规要求越来越高。低代码平台作为企业数字化的核心工具,其权限管理不仅要保障数据不泄露、操作不越权,还要满足行业监管和法律法规的要求。 很多企业误…

2025-11-06

2025-11-06CF补题 Problem - 515C - Codeforces(1400)(string+a little factorial) 这题妙在把各个数字阶乘转换成仅含有2 3 5 7 数字,然后直接求解 要对每个数的阶乘进行换算[!tip]9 is 7!*8*9=7!*3!*3!*2!8 is …

低代码权限管理常见场景解决方案:精准适配不同业务需求

低代码平台的核心优势是 “快速适配多元业务”,而权限管理作为保障业务安全的关键,必须跟着场景走。很多企业在设置权限时,容易陷入 “一刀切” 的误区 —— 用一套权限配置应对所有业务场景,结果要么出现 “权限不…