前端项目代码检查、格式化、Git提交消息规范

代码逐风说
• 阅读 739

pnpm workspace monorepo 这篇文章中讲述了一个单仓多包项目应该如何创建管理。但该项目可能会有多人共同开发,而每个人的开发习惯都不尽相同,所以在规范协商后还需要借助工具对项目进行约束,以确保该项目的开发不会有过多的个人风格。

代码格式化与 Git 仓库工具

接下来,我们在项目中将使用以下工具约束管理项目代码:

  • eslint
  • eslint-config-prettier
  • eslint-plugin-prettier
  • prettier
  • husky
  • lint-staged
  • commitzen
  • @commitlint/cli
  • @commitlint/config-conventional
  • cz-conventional-changelog

eslintprettier 大家都知道是用来规范代码和格式化代码的,在 vscode 中很常用,但如果团队中有人不用 vscode,而是用记事本这种软件,你又该如何应对呢?这时候就需要用到这两个工具了。

eslint-config-prettiereslint-plugin-prettier 两个是解决 eslintprettier 配置冲突的,想要详细解释请查看官网。

husky 是用来管理 git hooks 的,比如说在代码上传前对代码进行格式化,又或者对 commit-msg 进行校验等。

lint-staged 是用来过滤文件的。通常我们在项目中只改了一个文件,但运行代码格式化 prettier 时会对整个项目进行格式化,这会造成时间/资源的浪费,因此我们需要用这个工具对文件过滤,只格式化改动的的文件。

commitzen@commitlint/cli@commitlint/config-conventionalcz-conventional-changelog 几个工具都是规范 git commit 内容的。


实操

接着上一篇文章新建的项目,对其进行约束管理。

安装代码格式化工具

仅安装 eslintprettier 并不能让格式化符合我们的预期,因此我们还要安装 eslint 的插件来更好的对代码开发。

pnpm add -w -D eslint prettier eslint-config-prettier eslint-plugin-prettier @typescript-eslint/parser @typescript-eslint/eslint-plugin

新建这几个文件并填入相关配置

  • .eslintrc
  • .prettierrc
  • .eslintignore
  • .prettierignore

.eslintignore.pretterignore 都是用来过滤文件不执行检验和格式化的,因此填入的内容是一样的。

node_modules/
dist/
pnpm-lock.yaml
README.md

.eslintrc

{
  "root": true,
  "parser": "@typescript-eslint/parser",
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "prettier"
  ],
  "plugins": ["@typescript-eslint", "prettier"],
  "rules": {
    "prettier/prettier": "error",
    "arrow-body-style": "off",
    "prefer-arrow-callback": "off"
  }
}

.prettierrc

.prettierrc 的配置需要团队之间去协商,这里仅代表我个人,具体的参数配置可以查看 prettier 文档1

{
  "semi": true,
  "singleQuote": true,
  "tabWidth": 2,
  "printWidth": 120
}

此时代码格式化工具已配置完毕,我们在根目录的 package.json 添加指令尝试一下

{
    ...,
    "scripts": {
        ...,
        "lint": "eslint ./ --ext .ts,.js,.jsx,.tsx,.json --max-warnings=0",
        "format": "prettier --config .prettierrc . --write"
    }
}

指令已经添加,解释一下这两个指令:

  1. lint 指令,使用 eslint 对当前目录及所有子目录中包含 ts,js,jsx,tsx,json 后缀的文件都进行代码检测,具体参数请查看 eslint 官方文档2
  2. format 指令,使用 prettier 的配置文件 .prettierrc 对当前目录及所有子目录中的文件都进行文件格式化,具体参数请查看 prettier 官方文档1

目前我们的代码是这样的

前端项目代码检查、格式化、Git提交消息规范

这里我们单独运行指令看看

pnpm run lint

前端项目代码检查、格式化、Git提交消息规范

通过截图可以看出,代码极其不规范,Eslint 报了一大堆错误,该指令目前符合我们的预期,接下来运行 format 指令

pnpm run format

前端项目代码检查、格式化、Git提交消息规范

很好,文件都进行了格式化,该指令也符合我们的预期,此时再次运行 pnpm run lint 指令进行代码检查。

前端项目代码检查、格式化、Git提交消息规范
前端项目代码检查、格式化、Git提交消息规范

发现位于 packages/space-play/index.ts 文件有个变量没有用到,先删除掉再运行 pnpm run lint 指令。

前端项目代码检查、格式化、Git提交消息规范

此时的代码检查已经完成。

但是有个问题,修改了文件后每次都要单独运行 pnpm run lintpnpm run format 指令,这对我们的开发很不方便,因此我们要引入一个工具 onchange 帮我们监听文件的存储变动,而后自动格式化文件。

pnpm run -w -D onchange

安装好后在根目录的 package.json 文件新增一条指令

{
    ...,
    "scripts": {
        "format-auto": "onchange **/* -- prettier --config .prettierrc --write {{changed}}"
    }
}

运行指令看看会有什么变化

pnpm run format-auto

前端项目代码检查、格式化、Git提交消息规范

可以看到 onchange 工具已经在监听,并且手动修改了 apps/play1/index.ts 文件后,执行了 prettier 格式化。

至此,代码检查和格式化已经完成。

Git 仓库相关

项目中采用 husky 工具对 git hooks 进行管理,这里用到的钩子为 pre-commitcommit-msg

pnpm add -w -D husky

添加 husky 钩子有两种方式,一种是通过命令添加,一种是通过 .huskyrc 文件添加。

文件添加的方式是在根目录新建 .huskyrc 文件,并在里面写入钩子,钩子的值时指令运行,这里不做叙述。

{
    "hooks": {
        "pre-commit: "",
        "commit-msg": ""
    }
}

Git Hook: Pre-Commit

我们采用的方式是通过命令添加,这里先添加 pre-commit 钩子用于在 git commit 前执行 eslint 代码检查,如果不通过则取消 git commit

npx husky add .husky/pre-commit "pnpm run lint"

指令已经添加,试一试添加一条 git commit:

前端项目代码检查、格式化、Git提交消息规范

好的,通过截图可以看到,在添加 git commit 时已经运行了 pnpm run lint 指令,下面我们将通过新增一个工具 lint-staged 在进行 git-commit 时对文件进行过滤,仅对本次修改的文件进行代码检查。

pnpm add -w -D lint-staged

新建一个文件 .lintstagedrc.js,为什么这个文件要添加一个 .js 的后缀?因为在这个文件里需要写一点代码对文件进行过滤:

const { ESLint } = require('eslint');

const removeIgnoredFiles = async (files) => {
  const eslint = new ESLint();
  const ignoredFiles = await Promise.all(files.map((file) => eslint.isPathIgnored(file)));
  const filteredFiles = files.filter((_, i) => !ignoredFiles[i]);
  return filteredFiles.join(' ');
};

module.exports = {
  '*': async (files) => {
    const filesToLint = await removeIgnoredFiles(files);
    return [`eslint ${filesToLint} --max-warnings=0`];
  },
};

添加了代码后,打开 .husky/pre-commit 文件,将里面的内容替换:

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

pnpm run lint # 这条指令删掉
npx lint-staged # 新增该指令

在进行完上面的操作后,我们再次添加一条 git commit:

前端项目代码检查、格式化、Git提交消息规范

可以看到,lint-staged 已成功过滤文件并执行了 prettier 文件格式化和 eslint 代码检查。

Git Hook: Commit-Msg

为什么要添加 commit-msg 钩子?设想一下,某天你团队中的某个人在提交代码的时候仅写了个 ... ,你应该如何知道他修改了什么文件?时间长了之后,你再问他,他还记得这次的提交修改了什么东西吗?

所以,为了避免上述类似问题和规范化,我们需要对 commit-msg 进行限制,并借助 cz 工具帮我们问答式提交。

commit-msg 进行限制,我们需要安装这些包 @commitlint/cli, @commitlint/config-conventional

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

安装后新建 .commitlintrc.json 文件并写入相关规则,具体规则请自行搜索

{
  "extends": ["@commitlint/config-conventional"],
  "rules": {
    "scope-empty": [2, "never"]
  }
}

然后添加 husky 钩子在进行 git commit 时对提交内容校验。

npx husky .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

此时,限制 git commit -m 的钩子已经准备完毕,我们来添加一条 git commit 试试:

git add .
git commit -m "feat: 添加 commitlint 对 git commit 提交内容限制"

前端项目代码检查、格式化、Git提交消息规范

可以看到这条 git commit 已经被阻止了,原因就是在内容中我没有指定范围。
现在 commit-msg 已经被加了限制,那么我们安装 cz 工具对提交内容规范化,看看能不能通过。

需要安装的工具有 commitizen, cz-conventional-changelog:

pnpm add -w -D commitizen cz-conventional-changelog

安装完后新建 .czrc 文件并添加内容:

{
  "path": "cz-conventional-changelog"
}

然后再到根目录 package.json 添加一条新的指令:

{
    ...,
    "scripts": {
        ...,
        "cz": "cz"
    }
}

每次执行完 git add . 之后,我们可以通过运行 pnpm run cz 命令进行问答式的 commit-msg
前端项目代码检查、格式化、Git提交消息规范

从截图中可以看到,commit-msg 的内容已经规范化并通过了 commitlint 拦截。

至此,代码检查、文件格式化、版本控制提交消息规范已完成。


项目代码 - Monorepo Example

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
3年前
VBox 启动虚拟机失败
在Vbox(5.0.8版本)启动Ubuntu的虚拟机时,遇到错误信息:NtCreateFile(\\Device\\VBoxDrvStub)failed:0xc000000034STATUS\_OBJECT\_NAME\_NOT\_FOUND(0retries) (rc101)Makesurethekern
Wesley13 Wesley13
3年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
3年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这