# 代码风格自动化

作者: 王振州 时间: 2020-12-18

  由于每个人的编译器或代码风格不同, 而在协同开发项目的时候, 经常出现由于代码风格而出现的冲突, 或则 commit 信息杂乱不能分辨提交的代码解决了哪些问题和影响范围是哪些, 因此需要保证 git 上的代码和 commit 信息的风格一致性, 以减少 Bug,方便互相修改,短时间内能上手,而因此诞生了许许多多的工具。下面主要介绍下目前主流的前端代码格式化的工具。

# 1 Husky

Husky是 Git hooks 工具,可以防止使用 Git hooks 的一些不好的 commit 或者 push。

# 1.1 安装

npm install husky --save-dev
or
yarn add husky --dev
1
2
3

# 1.2 配置

// package.json
{
  "husky": {
    "hooks": {
      // commit 之前触发
      "pre-commit": "npm run test",
      // push 之前触发
      "pre-push": "npm  run test",
      "...": "..."
    }
  }
}
1
2
3
4
5
6
7
8
9
10
11
12

  在1.0.0之后的版本支持了使用.huskyrc.huskyrc.json.huskyrc.js配置文件,可以不放在package.json中。Husky 支持的Git hooks还是很全面的,如常用的pre-commitpre-push。这样我们就能再一些特定的时间点做一些事情。

# 2 Commitlint

  在有了 Husky 赋能之后,我们有能力在 Git 的钩子里做一些事情,首先不得不提的是代码的提交规范和规范的校验,优雅的提交,方便团队协作和快速定位问题。首推Commitlint

# 2.1 安装

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

// 生成配置文件commitlint.config.js,当然也可以是 .commitlintrc.js
echo "module.exports = {extends: ['@commitlint/config-conventional']};" > commitlint.config.js
1
2
3
4

# 2.2 配置

{
  "husky": {
    "hooks": {
      "pre-commit": "npm run test",
      "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS"
    }
  }
}
1
2
3
4
5
6
7
8

# 2.3 定制提交规范

# 2.3.1(注意冒号后面有空格)

<type><scope>: <subject>
1

常用的 type 类别

upd:更新某功能(不是 feat, 不是 fix)
feat:新功能(feature)
fix:修补bug
docs:文档(documentation)
style: 格式(不影响代码运行的变动)
refactor:重构(即不是新增功能,也不是修改bug的代码变动)
test:增加测试
chore:构建过程或辅助工具的变动
1
2
3
4
5
6
7
8

例子:

git commit -m 'feat: 增加 xxx 功能'
git commit -m 'bug: 修复 xxx 功能'
1
2

scope 影响范围

subject subject 是 commit 目的的简短描述,可以做一些配置,如最大长度限制。

# 2.3.2 commitlint.config.js 文件配置

rule 配置说明::rule 由 name 和配置数组组成,如:'name:[0, 'always', 72]',数组中第一位为 level,可选0,1,2,0 为 disable,1 为 warning,2 为 error,第二位为应用与否,可选always|never,第三位该 rule 的值。具体配置例子如下:

module.exports = {
  extends: ["@commitlint/config-conventional"],
  rules: {
    "type-enum": [
      2,
      "always",
      ["upd", "feat", "fix", "refactor", "docs", "chore", "style", "revert"],
    ],
    "type-case": [0],
    "type-empty": [0],
    "scope-empty": [0],
    "scope-case": [0],
    "subject-full-stop": [0, "never"],
    "subject-case": [0, "never"],
    "header-max-length": [0, "always", 72],
  },
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

  这里列出了大部分常用的配置,其它的可以参考 Commitlint 网站,具体使用例子: 这里我们使用错误的提交方式,最上面的是自动测试的脚本,大家可以忽略,husky 给出了 commit-msg 的 input 为 xxx,触发了 subject-empty,type-empty 两个规则,提交不符合规范,被拦了下来。如果是正确的提交,例子如下:

# 2.3.3 .cz-config 文件配置

module.exports = {
  types: [
    {
      value: "docs",
      name: "docs: 仅仅修改了文档,比如README, CHANGELOG, CONTRIBUTE等等",
    },
    { value: "chore", name: "chore:  改变构建流程、或者增加依赖库、工具等" },
    { value: "feat", name: "feat:  新增feature" },
    { value: "fix", name: "fix:  修复bug" },
    { value: "merge", name: "merge:  合并" },
    { value: "perf", name: "perf:  优化相关,比如提升性能、体验" },
    { value: "refactor", name: "refactor:  代码重构,没有加新功能或者修复bug" },
    { value: "revert", name: "revert:  回滚到上一个版本" },
    {
      value: "style",
      name: "style:  仅仅修改了空格、格式缩进、逗号等等,不改变代码逻辑",
    },
    { value: "test", name: "test:  测试用例,包括单元测试、集成测试等" },
  ],
  scopes: [{ name: "cli" }, { name: "工具" }, { name: "模块" }],
  messages: {
    type: "选择要提交的更改类型:",
    scope: "\n此更改影响的范围(可选):",
    customScope: "此更改影响的范围:",
  },
  allowCustomScopes: true,
  allowBreakingChanges: ["feat", "fix"],
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

下面我们就可以使用 git-cz 进行提交代码了

# 3 Lint-staged

  在我们介绍了 Husky、Commitlint 之后,来看一个前端文件过滤的工具Lint-staged,代码的格式化肯定会涉及到文件系统,一般工具会首先读取文件,格式化操作之后,重新写入。对于较大型的项目,文件众多,首先遇到的就是性能问题,虽然如 Eslint 之类的也有文件过滤配置,但毕竟还是对于匹配文件的全量遍历,如全量的.js文件,基本达不到性能要求,有时还会误格式化其他同学的代码,因此我们引入 Lint-staged,一个仅仅过滤出 Git 代码暂存区文件(被 committed 的文件)的工具。

# 3.1 安装

npm install --save-dev lint-staged husky
1

# 3.2 配置

首先明确一下,Lint-staged 仅仅是文件过滤器,不会帮你格式化任何东西,所以没有代码规则配置文件,需要自己配置一下,如:.eslintrc.stylelintrc等,然后在package.json中引入。

{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.js": ["eslint --fix", "git add"]
  }
}
1
2
3
4
5
6
7
8
9
10

当文件变化,我们git commit它们,pre-commit钩子会启动,执行lint-staged命令,我们对于lint-staged如上文配置,对本次被 commited 中的所有.js文件,执行eslint --fix命令和git add,命令,前者的的目的是格式化,后者是对格式化之后的代码重新提交。

除了在package.json中配置,也可以在.lintstagedrclint-staged.config.js文件中,lint-staged的常用选项除了liners之外,还有ignoreconcurrent等,具体参考文档:

{
  "lint-staged": {
    "linters": {
      "*.{js,scss}": ["some command", "git add"]
    },
    "ignore": ["**/dist/*.min.js"]
  }
}
1
2
3
4
5
6
7
8

对于文件的过滤,lint-staged的格式如下:

{
  // 项目中以 .js 结尾的文件
  "*.js": "eslint",
  // 项目中以 .js 结尾的文件
  "**/*.js": "eslint",
  // .js文件在src目录中
  "src/*.js": "eslint",
  // .js文件在src目录内和下面的任何位置
  "src/**/*.js": "eslint"
}
1
2
3
4
5
6
7
8
9
10

lint-staged提供的功能远不止于此,它只是平台,具体的格式化工具的搭配有很多,如对于图片的、样式的、.tsx.md等文件的。

# 4 Prettier

Prettier是一个支持多语言的代码格式工具,如常用的:jsjsxVueFlowTsHTMLCSS等,非常全面,将代码解析为 AST,然后重新组装,目的是最终输出风格统一的代码,对比 eslint 对 error 的 fix 要强一些,如最大长度的改动,eslint 只是对有问题的地方进行格式化修改,不改动源代码风格,而 prettier 是对全量的代码进行格式化。

# 4.1 安装

npm install --save-dev prettier
or
yarn add prettier --dev
1
2
3

# 4.2 配置

// package.json
{
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,json,css,md}": ["prettier --write", "git add"]
  }
}
1
2
3
4
5
6
7
8
9
10
11

这里我们结合之前用到的huskylint-staged,默认 prettier 是直接标准输出到终端的,--write,这个配置代表直接改写文件。 prettier 让我们专注于业务逻辑,无需再纠结代码风格,配合其它工具,实现了代码提交到仓库前,统一格式化。

# 5 使用截图

完整代码和配置