前言

之前在公司推行了工程化和项目规范,其中就涉及到了提交校验和代码校验,当时没啥时间写文,这会来补上

我将在文中一步一步构建一个 typescript 模板库,模板细节就不管了,注意力放在规范校验上

代码校验

首先是代码的规范问题,这边通过 eslint + prettier + editorconfig 来实现

eslint

eslint 用于规范咱们写的代码,接入其实很简单,官方提供了一个 CLI,我们在项目根目录下执行下面命令

1
pnpm create @eslint/config

在 CLI 中选择你自己需要的配置和代码格式喜好即可,我这边生成的 .eslintrc.cjs 配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
overrides: [],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
rules: {
indent: ['error', 2], // 缩进两个空格
'linebreak-style': ['error', 'unix'], // 换行符统一为 lf
quotes: ['error', 'single'], // 字符串单引号
semi: ['error', 'always'], // 需要分号
},
};

这边附上个人总结的 .eslintignore 中的规则,放在项目根目录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
node_modules/**/*
types/**/*
build/**/*
dist/**/*
es/**/*
lib/**/*

**/*.png
**/*.jpg
**/*.jpeg
**/*.gif
**/*.svg

**/*.css
**/*.scss
**/*.sass
**/*.less
**/*.stylus
**/*.styl

**/*.ejs

测试一下效果

双引号报错了

prettier

prettier 用于各种代码格式化,主要负责 eslint 不处理的文件的格式化,规则方面需要注意尽量别跟 eslint 冲突

首先安装依赖

1
pnpm add prettier -D

接着配置规则,规则写在 .prettierrc 文件中,存放于项目根目录:

1
2
3
4
5
6
7
8
9
10
11
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"bracketSpacing": true,
"bracketSameLine": true,
"arrowParens": "always"
}

当然也有对应的忽略规则文件,不过这个对我们校验并不影响,可有可无就不贴出来了

editorconfig

editorconfig 是一个大多数编辑器都支持的格式化配置文件,不走我们的校验流程

该配置是为了在编辑器没有配置使用 prettier 或者 eslint 来格式化代码时,起到兜底的效果,配置尽量别跟 eslintprettier 规则冲突

其格式化后的代码不一定 100% 过校验,所以有条件还是在编辑器里配置下格式化设置比较好

这边贴出 .editorconfig,同样是放在根目录:

1
2
3
4
5
6
7
8
9
10
11
12
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

[{*.md}]
trim_trailing_whitespace = false

提交校验

接着就是提交校验,这边选择了一个比较出名的开源提交规范 conventional

根据该规范衍生出了非常多的校验工具和提交生成工具

这些形形色色的工具都提供了自定义规范的能力,我个人实践下来 conventional 几乎已经覆盖了所有场景,就不自定义了,有需要可以查看下面各种工具的文档

commitizen

commitizen 是一个非常知名的 git-commit 工具脚手架,可以根据适配器构建出各种规范下的 commit-msg,官方默认推荐的适配器是基于 conventional 规范的 cz-conventional-changelog

首先在项目中安装本体和适配器

1
pnpm add commitizen cz-conventional-changelog -D

接着在 package.json 中配置适配器,添加如下配置

1
2
3
4
5
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
}

先初始化仓库 git init

然后我们修改任意代码,执行以下命令提交代码

1
2
git add *
pnpm cz # commitizen 脚手架

此时控制台上会出现一个交互式的提交记录生成界面

交互式提交生成

我们跟随引导完成交互即可生成出符合 conventional 规范的提交记录

commitlint

生成提交记录的工具有了,接下来就是校验提交记录的工具

commitlint 是一个非常出名的提交校验工具,也能通过配置使用不同的提交规范,官方推荐的默认配置同样也是基于 conventional 规范的 @commitlint/config-conventional

首先还是安装本体和配置

1
pnpm add @commitlint/cli @commitlint/config-conventional -D

接着在项目根目录新建一个 commitlint.config.cjs 文件,用来配置 commitlint 的校验规范

1
2
// commitlint.config.cjs
module.exports = { extends: ['@commitlint/config-conventional'] };

至此可以开始测试了,windows 环境的同学需要在 powershell 下执行该命令

1
"I'm Test msg" | pnpm commitlint

该提交明显是不规范的,控制台会报错

commitlint报错

我们换一个符合规范的提交试试

1
"feat(array): add flat function" | pnpm commitlint

控制台什么都不会输出,说明校验成功了

git-hooks & husky

git-hooks

虽然说是能校验了,但是如何做到 提交前校验我们的提交信息 并且 能根据结果中断提交呢?

此时 git-hooks 登场,我们只需要在指定的钩子中非 0 退出进程即可中断当前命令,根据 git 官方文档中的 commit-msg 部分

The hook is allowed to edit the message file in place, and can be used to normalize the message into some project standard format. It can also be used to refuse the commit after inspecting the message file.

commit-msg 钩子中校验提交信息并决定是否通过比较合适

编写 git-hooks 也很简单,只需在 .git/hooks 目录下新建钩子名的文件就行,同时也能通过 core.hooksPath 来修改钩子存放目录

可这个项目是一个模板,每次拉取安装依赖后如果还需手动设置 git-hooks 会显得十分繁琐,此时 husky 登场

husky

首先先在项目中安装 husky

1
pnpm add husky -D

接着执行该命令来一键配置 git-hooks

1
pnpm husky install

该命令会在项目根目录中生成 .husky 目录,并且会将 core.hooksPath 设置为 .husky

接着再使用 husky add 来添加钩子

1
pnpm husky add .husky/commit-msg "echo I_AM_TEST_MSG"

我们随便修改文件提交一次代码,应该可以看到控制台上打印 I_AM_TEST_MSGhusky 安装成功

校验提交

接着我们来自定义钩子的内容,用编辑器打开 .husky/commit-msg 并修改为以下内容

1
2
3
4
5
6
#!/bin/sh
export FORCE_COLOR="1" # 额外添加的环境变量,用于强制输出彩色

. "$(dirname "$0")/_/husky.sh" # husky 自动生成的代码,我们不用管

pnpm commitlint --edit $1 # commitlint 校验

其中 pnpm commitlint --edit $1 就是咱们的关键代码,--edit 表示校验提交信息文件,而不是提交信息的字符串

且根据官方文档

It takes a single parameter, the name of the file that holds the proposed commit log message. Exiting with a non-zero status causes the command to abort.

commit-msg 钩子被传入一个参数,该参数为提交信息存储的文件名,在 bash$0 固定为当前脚本的路径,$1 就是我们需要的提交文件名,所以将 $1 传给 --edit

来测试一下,随便修改文件,commit 一个不规范的提交

1
2
git add *
git commit -m test

会提示以下信息,且提交命令中断

提交报错

再使用 pnpm cz 提交规范的信息,会发现没有报错且提交成功了

校验代码

大伙肯定都想到要用这个钩子进行代码校验了,但这边有一个细节上的问题,如果我们只是普通的使用 eslint 无脑校验,代码量上去后,每次提交都需要等待全量校验完成,十分耗时

所以还需要额外添加一个校验库 lint-staged,该库可以做到增量校验

首先安装依赖

1
pnpm add lint-staged -D

接着在根目录新建 .lintstagedrc.cjs 文件

1
2
3
4
5
// .lintstagedrc.cjs
module.exports = {
// 用 eslint 和 prettier 增量校验 src 目录下所有指定后缀的文件
'./src/**/*{js,jsx,ts,tsx,md,html,vue}': ['eslint', 'prettier'],
};

最后再利用 git-hooks 进行代码校验

新建 .husky/pre-commit 文件,其内容为

1
2
3
4
5
6
#!/bin/sh
export FORCE_COLOR="1" # 额外添加的环境变量,用于强制输出彩色

. "$(dirname "$0")/_/husky.sh" # husky 自动生成的代码,我们不用管

pnpm lint-staged

我们再次写一段不规范的代码测试一下

双括号哒咩

然后使用 pnpm cz 进行提交,果然是报错了

eslint校验报错

修改成规范的代码再次提交,正常通过

发布版本(可选)

如果你还需要将当前库进行版本管理,发布到公开、私有 npm 仓库上,那么还需要一个版本生成工具 standard-version

standard-version

该工具的默认配置同样基于 conventional 规范,它会扫描我们的提交记录,并使用 semver 规范来生成版本号

首先还是安装依赖

1
pnpm add standard-version -D

为了方便使用我们在 package.jsonscripts 中添加脚本

1
"release": "standard-version"

当我们项目需要发版的时候,只需要执行 pnpm release 即可自动更新版本号,并且会在根目录下根据提交记录生成更新日志 CHANGELOG.md,同时也会在 git 中打上 tag

此时我们的开发流程应当是:

  • 修复 bug / 增加特性

  • pnpm cz 对每一个 bug / 特性 单独的进行规范的提交

  • pnpm release 发版

  • git push && pnpm release 推送代码并发布到 npm 仓库

小修小改

package.jsonscripts 中加入如下脚本

1
"prepare": "git init && pnpm husky install"

prepare 会在 pnpm install 安装依赖后自动调用,如此这般,我们模板的使用流程被简化至:

  • git pull xxx

  • cd xxx

  • pnpm install

最后

至此,一套闭环的代码、提交校验流程就搞定了

后续打算把在公司做的 CLI 也拿出来写一写,还挺好用