背景

团队协作中经常遇到这样的问题:

  1. 代码风格不统一

可以使用 linter 使代码风格统一。

  1. 使用 linter 检测之后有非常多的格式问题,手动修改很麻烦

可以使用 linter 命令来修复错误。比如 eslint 就可以 eslint --fix

  1. 使用命令修复的时候,不小心修改了他人代码,很容易造成冲突。
  2. 如果一个项目以前没有用过 linter,如何最方便地开始使用并且尽量不改动之前的代码?

解决以上问题的一个方案就是,在提交代码的时候,自动修复格式问题,并且只修复自己改动的代码。

具体实现可以借助于 husky + lint-staged + prettier 这几个工具。

最终效果如下图所示:

使用 husky+lint-staged+prettier 优化代码格式 - 图1

使用

首先安装包 eslint 相关的包,如:

  1. # Node.js 可以使用 eslint-config-egg
  2. $ tnpm i eslint eslint-config-egg babel-eslint -D
  3. # 或 React 项目使用 eslint-config-airbnb
  4. $ tnpm i eslint eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-config-airbnb -D

然后在项目根目录创建 .eslintrc 文件,并写入对应的配置,以 eslint-config-airbnb 为例:

.eslintrc

  1. {
  2. "extends": "airbnb"
  3. }

接下来再安装 prettier lint-stagedhusky

  1. $ tnpm i prettier lint-staged husky -D

简单介绍一下几个工具:

  • prettier 用来优化代码格式,比如缩进、空格、分号等等
  • husky 用于实现各种 Git Hook。这里主要用到 pre-commit这个 hook,在执行 commit 之前,运行一些自定义操作
  • lint-staged 用于对 Git 暂存区中的文件执行代码检测

接下来配置 package.json

  1. "scripts": {
  2. "lint": "eslint . --ext .js",
  3. "prettier": "prettier --trailing-comma es5 --single-quote --write '**/*.{js,json,md}'",
  4. },
  5. "husky": {
  6. "hooks": {
  7. "pre-commit": "lint-staged"
  8. }
  9. },
  10. "lint-staged": {
  11. "**/*.js": [
  12. "prettier --trailing-comma es5 --single-quote --write",
  13. "eslint",
  14. "git add"
  15. ]
  16. },

scripts

  • lint 检测 js 代码的 eslint 错误
  • prettier 使用 prettier 优化代码的格式

如果一个项目之前没有使用过 linter,现在加上了,并且需要处理所有的代码格式,就可以使用 tnpm run prettier

--trailing-comma es5 表示使用 ES5 支持的拖尾逗号;--single-quote 表示使用单引号。prettier 的所有参数详见 https://prettier.io/docs/en/options.html

这些参数即可以在命令中配置,也可以使用配置文件 .prettierrc 来指定,如:

  1. {
  2. "singleQuote": true,
  3. "trailingComma": "es5"
  4. }

在优化代码格式的时候,有些文件不需要进行处理,则可以通过 .prettierignore 文件来配置:

  1. dist/
  2. node_modules
  3. *.log
  4. run
  5. logs/
  6. coverage/

husky

husky 里面定义了一些 Git 的钩子。

上面的示例中,"pre-commit": "lint-staged" 的含义就是在 pre-commit 阶段(也就是 commit 之前)执行 lint-staged 命令。

lint-staged

如上所述, lint-stagedpre-commit 的时候执行。lint-staged 里面定义了需要对 Git 暂存区中的文件执行的任务。

在该 package.json 示例中主要有一个任务: **/*.js, 即对暂存区中所有 js 文件依次执行下面的操作:

  • prettier --trailing-comma es5 --single-quote --write
  • eslint
  • git add

也就是先优化暂存区中的 js 代码格式,再进行 eslint 检测,最后再执行 git add,将优化后的代码添加到暂存区。暂存区中的代码文件,就是这几个命令的参数。

如果 eslint 步骤抛错了,则表示代码格式不符合 eslint 规范,进而导致 pre-commit 这个钩子就会抛错,最终导致 commit 操作失败。

因为 eslint 也只会检测 lint-staged 中的代码,也就是自己修改过的代码。所以即避免了影响他人代码,同时也避免了因他人代码格式问题造成自己的代码不能提交。

其他

huskylint-staged 配合起来还有非常多的用处。

比如删除已经被 Git 追踪的文件。

比如 run/ 目录是代码运行时生成的目录。如果一开始没有将 run/ 添加到 .gitignore 里面,则每个人提交代码的时候都会提交自己的 run/ 目录。由于每个人 run/ 目录里面的文件很可能不一致,所以很容易造成冲突。

而且一旦文件已经被 Git 追踪,再将其添加到 .gitignore 里面,也无法在提交的时候忽略它。

这个时候,就可以在 pre-commit 阶段,利用 "lint-staged" 的任务删除暂存区里面的 run/

如下所示:

  1. "lint-staged": {
  2. "**/*.js": [
  3. "prettier --trailing-comma es5 --single-quote --write",
  4. "eslint",
  5. "git add"
  6. ],
  7. "run/*": [
  8. "git rm --cached"
  9. ]
  10. },

然后再在 .gitignore 里面添加上 run/,这样以后再提交代码的时候,就再也不会将 run/ 提交到 Git 仓库了。