一、项目规范的基石——husky 与 lint-staged

19,583 阅读7分钟

(注:文末有直接集成两个工具的方法,与单独集成不冲突。)

一、husky

注:本文引入的 husky 都是 8.0.0 以上的版本,老版本的使用可能与下文描述的不一致!

1. husky 是什么?

husky 的 README 开篇是这么描述的:

Modern native Git hooks made easy (轻松创建现代化的原生 git hooks) Husky improves your commits and more 🐶 woof!

最重要的就是:它可以在项目中植入你设定的 git hooks,在 git 提交代码的前后,你预设的 git hooks 可以得到执行,以对代码、文件等进行预设的检查,一旦检查不通过,就可以阻止当前的代码提交,避免了不规范的代码和 git 提交出现在项目中。

git hooks 是本地的,不会被同步到 git 仓库里。为了保证每个人的本地仓库都能执行预设的 git hooks,于是就有了 husky。

2. husky 的特性

husky 的 官方文档 是这么描述的 (直译):

  • 零依赖,轻量级的 (6k)
  • 由 git 的新特性提供支持
  • 遵循关于 npm 和 Yarn 自动安装的最佳实践
  • 提供用户友好的消息提示
  • 提供可选的安装
  • husky 4 支持:
    • macOS, Linux, Windows 三大操作系统
    • Git GUI
    • 自定义目录
    • monorepo

官方文档 列举了非常多牛X轰轰的项目在使用 husky。

3. 引入 husky

这里先介绍如何引入单独的 husky,下文会介绍如何同时引入 husky 和 lint-staged。如果你期望同时引入这两个工具,可以忽略这一小节。

3.1 空项目

如果还没有创建项目,你可以通过以下命令中的某一条,来初始化一个带有 husky 的项目:

npx husky-init               # npm
npx husky-init               # Yarn 1
yarn dlx husky-init --yarn2  # Yarn 2+
pnpm dlx husky-init          # pnpm

上面的命令执行完之后,只需要再执行安装依赖的命令即可:

npm install   # npm
yarn          # Yarn
pnpm install  # pnpm

这是官方推荐的做法。如果你想在目前已有的项目中引入 husky,可参考下一节。

3.2 已有项目

要想在已有的项目中使用 husky,可按如下步骤操作:

  1. 安装 husky

    npm i husky -D # npm
    yarn add husky -D # yarn
    pnpm i husky -D # pnpm
    
  2. 启用 git hooks

    npx husky install # npm
    pnpx husky install # pnpm
    
  3. 加入 husky prepare 命令

    • 直接在 package.jsonscripts 里加上如下命令:
      {
        "scripts": {
          "prepare": "husky install"
        }
      }
      

4. husky 的使用

前置知识:git hooks

git hooks 的分类如下

  • 客户端 hooks
    • 提交工作流
      • pre-commit
      • prepare-commit-msg
      • commit-msg
      • post-commit
    • email 工作流
      • applypatch-msg
      • pre-applypatch
      • post-applypatch
    • 其它
      • pre-rebase
      • post-rewrite
      • post-checkout
      • post-merge
      • pre-push
      • pre-auto-gc
  • 服务器端 hooks
    • pre-receive
    • update
    • post-receive

注意:在客户端 hooks 中,developer 可以通过 git comiit -m "commit message" -n (-n 等价于 --no-verify) 来忽略掉 pre-commit hook 的执行!

使用 husky

使用 husky 的时候,我们通常只关注 提交工作流 的几个 hooks,用得最多的一个是 pre-commit

使用 hosky 的时候,通常是用它来创建一系列的 git hooks,并在对应的文件中撰写 shell 脚本代码。

下面是官方示例中的一个,创建了 pre-commit hook 文件。

  • 创建一个 hook: husky add <file> [cmd]
    • file: 指定保存命令的文件,通常是在 .husky 目录下
    • cmd: 指定 git hooks 的名字,最常使用的是 pre-commit
    # 创建一个 pre-commit 的 hooks 文件
    npx husky add .husky/pre-commit "npm test" # npm
    pnpx husky add .husky/pre-commit "npm test" # pnpm
    git add .husky/pre-commit
    # 创建好这个文件之后,你就可以根据你的需要去编写这个 shell 脚本了
    

二、lint-staged

1. lint-staged 是什么?

背景

随着 Web 前端开发的逐渐大前端化,Web 前端项目的体积变得越来越大,一个项目的参与者也越来越多,对代码规范、代码检查的要求越来越高。因此越来越多的项目要求 developer 在提交代码之前,必须让自己的代码通过如 ESLint, Stylelint 等代码格式化工具的格式化 (规范化)。

在起初的开发过程中,项目小,代码量少,全量跑一次 lint 的时间也相对较短。但随着项目体量的增大,全量跑一次 lint 的时间越来越长。而我们都知道,如果每一个人提交的代码都是通过了 lint 工具的格式化,那么在一次提交的时候,可能没有规范化的文件,就仅仅是当前 developer 即将提交的这些。如果在一次提交的时候,只对这一部分代码做规范化,那将大大缩短 developer 提交代码的速度,于是就诞生了一个工具:lint-staged

介绍

通过这个工具诞生的背景,我们可以知道, lint-staged 是一个专门用于在通过 git 提交代码之前,对暂存区的代码执行一系列的格式化。当 lint-staged 配合 git hooks 使用时,可以在 git 提交前的 hook 中加入 lint-staged 命令,这样就能在提交代码之前,对即将提交的代码进行格式化,成功之后就会提交代码。

2. 引入 lint-staged

直接执行下面的脚本来安装 lint-staged 即可。

npm i lint-staged -D # npm
yarn add lint-staged -D # yarn
pnpm i lint-staged -D # pnpm

3. lint-staged 的使用

配置方式:

  • package.json 中的 lint-staged 配置项
  • JSON 风格或 YML 风格的 .lintstagedrc
    • .lintstagedrc.json
    • .lintstagedrc.yaml
    • .lintstagedrc.yml
  • .lintstagedrc.mjs.lintstagedrc.config.mjs
  • .lintstagedrc.cjs.lintstagedrc.config.cjs
  • lint-staged.jslint-staged.config.js

package.json 为例:

{
  "lint-staged": {
    "<glob-pattern>": <command>
  }
}
  • <command> 可以是单个命令的字符串,也可以多个命令组成的数组。使用 js 作为配置文件时,还可以是导出一个如下类型的函数:

      (filenames: string[]) => string | string[] | Promise<string | string[]>
    

虽然配置好了 lint-staged,但目前还不能自动地使用它,因为通常它是放在 Git 的 pre-commit 阶段去执行,因此要在 .husky/pre-commit 文件中增加执行 lint-staged 的命令

# 如果使用的是 npm/yarn 且 npm 版本为 v8 及以下,就加下面的命令
npx lint-staged

# 如果使用的是 npm/yarn 且 npm 版本为 v9 及以上,就加下面的命令
npm exec lint-staged

# 如果使用的是 pnpm,就加下面的命令
pnpm exec lint-staged

# ! 注意,上面的这三个命令必须根据实际情况来选择,且只能存在一个

三、安装 husky 与 lint-staged 命令

注:版本更新

版本更新后,直接执行命令

npx mrm@2 lint-staged # npm/yarn
pnpx mrm@2 lint-staged # pnpm

时,只会补充 huskylint-staged 的命令,不再安装这两个依赖。

因此如果想同时集成这两个依赖,还需在上述命令执行完之前,先执行如下命令:

npm i husky lint-staged -D # npm
yarn add husky lint-staged -D # yarn
pnpm i husky lint-staged -D # pnpm

3.1 集成方式

二者的官方都推荐了使用 mrm 这个库来同时集成 husky 和 lint-staged。

在你的项目根目录下,直接执行如下命令:

npx mrm@2 lint-staged # npm/yarn
pnpx mrm@2 lint-staged # pnpm

执行命令之后,你就会看到你的 package.json 里多了一个 lint-staged 配置项,且根目录下多了一个 .husky 目录,里面就包含了 pre-commit 文件,里面包含了一个最基础的命令:npx lint-staged

在后续的开发工作中,任何需要在 pre-commit 阶段执行的命令,都可以添加到 .husky/pre-commit 文件中。

四、总结

本文详细介绍了 huskylint-staged 的集成。成功集成这两个工具之后,在项目根目录下会多出 .husky 目录,在 package.json 中会多出 lint-staged 配置项。

.husky/pre-commit 文件中存在

附:npx 查找规则

  1. /node_modules/.bin 目录下查找是否存在对应的命令,如果没有找到则执行第 2 步;
  2. 去查找全局安装的命令里是否有对应的命令,如果没有找到则执行第 3 步;
  3. 创建一个临时目录,下载命令对应的依赖,然后执行这个命令,完成之后就删除这个临时目录。

了解了这个规则之后,就可以放心地使用 npx 来执行一些命令了。如果期望项目里的命令在每一个 developer 那里都能有相同的表现,墙裂建议在项目内统一安装对应的 dependency。