Git 钩子是当今开发工作流程中最不可或缺的部分之一。钩子有助于在一个有多个贡献者的大型代码库中保持代码质量。随着提示、代码格式化和类型检查的引入,Git Hook的任务比以往更多。
对于前端开发者(或一般的JavaScipt开发者)来说,Husky是管理Git Hooks的首选。尽管Husky很受欢迎,但它缺乏并行化,而并行化可以加快钩子的执行速度。它还向node_modules
,这可能是一个问题。
在这篇文章中,我们将看看Lefthook,一个更快、更简单、更强大的Husky替代品,适合前端开发者。我们将通过把Lefthook添加到一个React和React Native应用的样本中,来看看Lefthook与Husky的对比情况。
什么是Lefthook?
基于JS的前端社区已经发展到用其他语言开发的工具现在支持JS开发。Lefthook是这一趋势的产物;它使用Go开发,声称是Node.js和Ruby的最快的polyglot Git Hooks管理器,但我相信它对其他堆栈也很有效。由于它是通过单一的二进制文件工作的,所以node_modules
目录受到的污染较少。
突出的特点
Lefthook在Git Hook管理器中脱颖而出,因为它有令人难以置信的功能,可以在没有任何管理麻烦的情况下加强开发工作流程。这里列出的所有功能在Husky中都是不可用的。
平行执行
Lefthook是用Go开发的,这使它在利用机器的并行化方面有更大的潜力;实现任务的并行执行只是一个单行问题。
并行执行是大规模应用的最重要要求之一。对于较大的提交,人们可以利用拼写检查、类型检查、ESLint和StyleLint等并行方式,为开发者节省大量时间。我将在后面分享一个React应用中的例子。
选择要检查的文件
Lefthook协助在有限的文件集上执行命令,有预置的速记工具、glob和RegEx过滤器,以及在子目录中运行的选项。
如果你在预提交任务中运行JS linters和StyleLints,这可能是超级有用的;理想情况下,类型检查任务将与完整的文件列表一起进行,而ESLint和StyleLint将被应用于分阶段文件。下面是选择文件来执行任务的例子。
-
Glob
pre-commit: commands: lint: glob: "*.{js,ts,jsx,tsx}" run: yarn eslint
-
速记本
pre-commit: commands: frontend-linter: glob: "*.{js,ts,jsx,tsx}" # glob filter for list of files run: yarn eslint {staged_files} # {staged_files} or {all_files} - list of files
-
自定义列表
pre-push: commands: frontend-style: files: git diff --name-only master # files with, diff with master. glob: "*.js" run: yarn stylelint {files}
独立的本地配置
虽然使用Git Hooks的目的是为了在几个开发人员工作时保持代码库的质量,但人们可能需要一种方法来绕过它,在他们的本地机器上以不同方式执行特定的钩子。Lefthook通过添加一个单独的文件来支持这种优化,以便在本地环境中以不同的方式管理Hooks。
让我们创建一个commit-msg
钩子来更好地理解本地配置。使用下面的代码来创建一个新的钩子。
lefthook add -d commit-msg
添加-d
将创建.lefthook/commit-msg
和.lefthook-local/commit-msg
目录。第一个是用于普通的项目级脚本;第二个是用于个人脚本,当任务只在创建者的机器上本地运行时,这些脚本将被使用。理想情况下,.lefthook-local
应该是.gitignore
的一部分。
脚本和运行器
使用Lefthook,你可以用任何编程语言创建自定义任务。这让我们可以自由地优化 Git 钩子,使其更快。
除此之外,我们还可以为这些脚本选择运行器,比如Docker VM。下面是一个用Bash运行器处理自定义脚本的简单例子。
让我们创建一个Bash脚本来检查.lefthook/commit-msg/template_checker
中的提交模板。
INPUT_FILE=$1
START_LINE=`head -n1 $INPUT_FILE`
PATTERN="^(ISSUE)-[[:digit:]]+: "
if ! [[ "$START_LINE" =~ $PATTERN ]]; then
echo "Bad commit message, see example: ISSUE-123: some text"
exit 1
fi
现在我们可以通过在lefthook.yml
文件中添加这段代码来要求Lefthook运行我们的Bash脚本。
commit-msg:
scripts:
"template_checker":
runner: bash
# "template_checker.js": # We can also use JS file and reference it here
# runner: node # It will be executed using node as a runner
# USING DOCKER AS RUNNER
# "docker_hook.js": # Similar file reference
# runner: docker run -it --rm <container_id_or_name> {cmd} # Here {cmd} => command
管道式执行
尽管并行执行是一个突出的特点,Lefthook也支持命令的管道执行。如果任务的执行需要管道化的功能,而序列中的任何命令都会失败,Lefthook就不会执行其他的命令,确保任务的顺利完成。
这对于那些需要在执行前进行数据库设置的任务来说是非常有帮助的。下面是一个小例子。
database:
piped: true
commandy
1_create:
run: rake db:create
2_migrate:
run: rake db:migrate
3_seed:
run: rake db:seed
配置的继承
Lefthook中的配置设置不仅限于本地和项目层面,我们还可以扩展配置。
配置的继承有助于确保产品或公司范围内的提交信息、安全审计和其他检查的同步。下面是如何扩展任何其他配置。
extends:
- ~/unicorns/configs/lefthook-extend-2.yml
在React/React Native中实现Lefthook
如果上述例子对作为React或React Native开发者的你来说并不直观,请不要担心;以下是如何在你的应用中利用Lefthook的示范。
我们将从安装Lefthook开始。
npm install @arkweid/lefthook --save-dev # or yarn add @arkweid/lefthook -D
一旦Lefthook安装完毕,你会在项目的根部看到lefthook.yml
;这是一个文件,它将容纳我们所有的工作和挂钩。记住,这是一个开发依赖性,是与本地或全球安装的Lefthook二进制文件的绑定。它把你从依赖关系的恶梦中解放出来。
替换Husky
本节假设你的应用程序已经集成了Husky;如果你的情况不是这样,请移到下一节。
从从你的项目中卸载Husky开始。
npm uninstall husky # or yarn remove husky
卸载后,你可以从项目中删除.husky
目录,或从package.json
中删除其声明,这取决于你的实现。
接下来,让我们把Git Hooks重置为默认值。
git config --unset core.hooksPath
rm .git/hooks/pre-commit
rm .git/hooks/pre-push
现在,把Husky的实现移到lefthook.yml
。
pre-commit:
commands:
sometest:
run: npm lint
pre-push:
commands:
anothertest:
run: npm audit
预提交钩子
让我们添加一个快速并行运行的预提交钩子,以确保我们的应用程序的代码在开发者提交时总是适合被合并的。请确保你的应用程序中启用了TypeScript。
因为我们已经安装了Lefthook(如果你从上面跳到这一节,请回顾之前的代码以获得安装帮助),让我们开始为我们的应用添加一个预提交钩子。我们把我们的预提交钩子分成四个任务,所有这些任务都可以并行运行。
- 类型检查
- ESLint
- 代码拼写检查器
- 马克顿链接检查
下面是我们的预提交钩子,所有四个任务都在并行运行。
pre-commit:
parallel: true
commands:
type-check:
glob: '*.{ts,tsx}'
run: yarn typecheck
eslint:
glob: '*.{js,ts,jsx,tsx}'
run: yarn lint:eslint:fix {staged_files}
stylelint:
glob: '*.{js,ts,jsx,tsx}' # For CSS-in-JS
run: yarn lint:style {staged_files}
spelling:
glob: '*.{js,ts,jsx,tsx,md}'
run: yarn cspell {staged_files}
markdown-link-check:
glob: '*.md'
run: npx markdown-link-check {staged_files}
正如你所看到的,我们利用了Lefthook的能力,为任务执行选择了一大块文件。文件的选择取决于任务,例如,类型检查必须在整个应用程序中执行,以确保类型安全,而lint、拼写检查和链接检查只适合于分阶段的文件。
提交消息钩子
接下来是提交消息钩子。这个钩子为我们省去了管理变更日志和提交信息可读性的麻烦。
我们在这里使用的是commitlint,但你也可以像前面提到的那样,使用其他库或你的自定义脚本与runners。下面是我们的commit-msg
钩子的代码,看起来。
commit-msg:
commands:
parallel: true
lint-commit-msg:
run: npx commitlint --edit
spell-check:
run: yarn cspell --no-summary {1}
预推送钩子
现在,是时候确保每当代码被推送到我们的仓库时,它都经过了良好的质量和安全测试。就像我们的预提交钩子一样,这些任务可以并行进行。下面是我们的预推送钩子。
pre-push:
parallel: true
commands:
test:
run: yarn test
packages-audit:
run: yarn audit
一言以蔽之
在我看来,Lefthook比其他的Git Hook管理库更有力,同时也给了我们更多的自由和简单。通过并行化,任务执行得更快,加上对自定义运行器的支持,Lefthook是在CI/CD环境中使用的一个不错的选择。配置的继承对于跨团队执行共同的编码实践有很大帮助。
如果你对Lefthook印象深刻并希望从Husky迁移,这里有迁移指南。
我还准备了一个Gist,可以把这里讨论的钩子添加到你的React和React Native应用中。请试一试吧。
The postA deep dive into Lefthook for React and React Nativeappeared first onLogRocket Blog.