代码规范与提交
husky
husky 是一个用于简化Git钩子(hooks)的设置的工具,允许开发者轻松地在各种Git事件触发时运行脚本。例如,在提交之前(pre-commit)、推送之前(pre-push)、或者在提交信息被写入后(commit-msg)等。
husky的使用可以提高项目团队的工作效率,确保代码库中的代码符合特定的质量标准。它通常与lint-staged一起使用,以在提交前自动执行代码的静态检查。
使用husky包括以下简单步骤:
添加husky到项目依赖。 配置Git钩子,使用husky的配置。 当相应的Git事件被触发时,定义的脚本就会自动执行。
- husky解决了git hook 的什么痛点? husky是如何将hooks跟package.json关联的?
git原生的钩子存储在项目的.git/hooks目录下,属于本地私有目录,不会被提交到git远程仓库。多人协作时候无法共享,可能出现配置不一样的情况。 安装husky后会修改git配置(git config),将git的原生钩子改成husky管理的脚本目录。开发者可以在packge.json和.husky进行配置
- 在前端工作流中,
husky
最常与哪些工具搭配使用?请至少列举两个,并说明husky
在这个组合中扮演的角色。
eslint commitlint prettier。角色:通过钩子进行触发。
-
pre-commit
和commit-msg
是两个最常用的 Git hook。请解释一下它们分别在什么时机触发,以及通常用它们来做什么?
Git 先触发 pre-commit 钩子(执行检查脚本) → 如果检查通过 → 直接使用 -m 后的内容作为提交信息,完成提交 → 如果检查失败 → 提交中断 检查代码语法和检查提交信息。
- husky v4 与 v5+ 在安装、配置和工作原理上的主要区别
husky v4 的钩子规则(比如 “提交前要跑 ESLint”)虽然写在 package.json
里能被 Git 跟踪,但实际执行钩子的脚本文件藏在本地 .git/hooks
(不被 Git 跟踪)。团队成员需要通过 npm install
手动触发脚本生成,本质是 “依赖安装步骤间接同步”,容易因为漏执行步骤导致钩子失效。
husky v5+ 的钩子规则直接以 .husky
目录下的脚本文件 存在(比如 .husky/pre-commit
),这些文件能被 Git 跟踪,所以 “规则可见”。团队成员拉取代码后,钩子脚本会直接同步到本地,再通过 prepare
脚本自动绑定 Git 配置,本质是 “依赖 Git 文件同步直接生效”,几乎不需要额外手动操作。
-
git commit 过程的变化:
如果pre-commit
钩子脚本以非零状态码退出(例如 ESLint 检查出错误,返回1
),Git 会立即中断整个提交流程,不会创建提交记录。终端会显示脚本的错误输出(如 ESLint 的报错信息),提示用户修复问题后重新提交。 -
husky 的实现方式:
husky 本身并不改变 Git 钩子的原生机制 ——Git 规定:任何钩子脚本如果以非零状态码退出,后续提交流程都会终止。 ** husky 的作用是将用户定义的命令(如eslint .
)包装到.husky/pre-commit
脚本中,当用户命令失败时,脚本会继承其非零退出码,从而触发 Git 的原生中断逻辑。简单说,husky 只是 “传递” 了命令的失败状态,借助 Git 本身的机制实现提交拦截。 -
现在一些 CI/CD 工具(如 GitHub Actions, GitLab CI)也能在代码推送到远程仓库后执行检查。既然如此,为什么我们还需要在本地通过
husky
做提交前的检查?这两者是重复的吗?
反馈速度:本地检查比 CI 快 10 倍以上,如果没有本地检查,错误代码可能被提交到远程仓库,导致:CI 任务频繁失败,浪费团队共享的 CI 资源,CI/CD 的核心作用是确保合并到主分支的代码符合生产标准
- 在一个大型项目中,
pre-commit
钩子可能需要运行 lint、类型检查和单元测试,导致每次提交等待时间很长。你有什么策略或建议来优化这个体验?
配合lint-staged只对提交代码检查 ,ESLint:通过 --cache
选项启用缓存(eslint --cache
),并行检查:run-p命令
lint-staged
lint-staged可以在git staged阶段的文件上执行代码检查(Linters),包括ESLint和Stylelint等。简单说就是,当开发者运行ESlint或Stylelint命令时,可以通过设置指定只检查通过git add添加到暂存区的文件,避免每次检查都把整个项目的代码都检查一遍,从而提高效率。
- lint-staged 如何获取 "staged files" 列表?调用了哪些 Git 命令?
lint-staged 本质是通过 Git 命令 查询暂存区状态来获取文件列表,核心命令是:
git diff --cached --name-only --diff-filter=ACMR
-
配置中可以使用函数 例如对不同类型的文件进行不同的规则匹配,函数效果更好,能根据文件的动态信息生成个性化的命令。
-
lint-staged 如何处理大量暂存文件?如何避免命令行长度限制? 将文件列表拆分成多个 “批次”,每个批次的文件名拼接后不超过长度限制。对每个批次分别执行命令(如
prettier --write file1.js file2.js ...
),直到所有文件处理完成。
commitlint
commitlint
是一个用于检查 Git 提交信息(commit message)是否符合规范的工具
- 除了
commitlint
,你还知道什么工具可以帮助开发者更方便地编写出符合规范的 Commit Message?
例如:cz-git 用 cz
生成信息 → commit-msg
钩子触发 commitlint
检查 → 检查通过才允许提交。
- 请深入解释 commit-msg 这个 Git Hook 的工作机制。当 husky 调用 commitlint 时,commitlint 是如何获取到你正在编辑的 Commit Message 内容的?
通过将msg放入临时文件中,然后将文件路径交给钩子脚本去进行校验。校验失败返回非0,代码非0停止终端提交。
- commitlint 内部是如何解析一个 Commit Message 字符串并进行规则校验的?你可以猜测一下它可能用到的技术或核心逻辑吗? 将字符串转换成结构化的数据,正则,配置,插件,错误处理。
eslint
ESLint 是一个针对 JavaScript(及衍生语言如 TypeScript、JSX)的静态代码分析工具。它通过预设或自定义的规则,在代码运行前检查潜在问题,比如语法错误、未使用的变量、不合理的逻辑结构,以及代码风格不一致(如缩进、引号类型)等,帮助开发者提升代码质量、减少 bug 并保持团队代码风格统一。
- AST 的定义及 ESLint 如何利用 AST 检查代码
解析生成 AST:通过解析器将源代码转换为 AST,使代码的语法结构可被程序 “理解”。
遍历 AST 节点:ESLint 会深度遍历 AST 的每个节点,触发配置中规则对特定节点类型的监听。
规则校验节点:每个规则本质是一个函数,会针对特定节点类型(如 CallExpression
)进行检查。例如,no-console
规则会监听 CallExpression
节点,判断其是否是 console.log
之类的调用,若是则标记为错误。
- TypeScript 为何需要 @typescript-eslint/parser?与 Espree 的本质区别
ESLint 本身无法直接处理 TypeScript 代码,必须依赖 @typescript-eslint/parser
,原因是:
TypeScript 包含大量 JavaScript 不具备的语法(如类型注解 : number
、接口 interface
、泛型 <T>
等),而 ESLint 默认的解析器 Espree 仅能解析标准 JavaScript 语法,无法识别 TS 特有语法,会导致解析失败。
prettier
Prettier 是一款专注于代码格式化的工具,核心功能是通过自动化方式,按照预设规则统一代码的格式风格(如缩进、引号、换行、空格等)。
- Prettier 与 ESLint/TSLint 的核心区别
Prettier:只负责代码格式(如缩进、引号、换行),不关心代码质量(如未定义变量、死循环、不合理的逻辑)。 ESLint/TSLint:主要负责代码质量检查(如语法错误、变量未使用、不符合最佳实践的逻辑),同时也包含部分格式规则(如缩进、分号)。
- Prettier 的工作原理及与正则替换的本质区别
Prettier 的流程如下:文件遍历与过滤:代码解析(生成 AST) :AST 遍历与代码生成:通过AST能够理解代码,而不是直接通过正则。
- eslint和Prettier的冲突
eslint-plugin-prettier
会把 Prettier 的格式化逻辑转换成一条 ESLint 规则(可以理解为 “将 Prettier 的规则注册到 ESLint 中”),这样 ESLint 在检查时,会把不符合 Prettier 格式的代码标记为 “ESLint 错误”。 eslint-config-prettier
则负责 “清场”,禁用 ESLint 自带的、可能与 Prettier 冲突的格式规则(比如 ESLint 的 indent
规则和 Prettier 的缩进逻辑可能不一致),避免出现 “同一处格式被两个工具判为‘错误’” 的矛盾。