一文讲透项目开发中如何保证代码规范化

437 阅读16分钟

在公司开发中,我们常常是团队合作进行开发,那么对于一个团队而言,代码规范往往是一个非常重要的东西。统一代码规范有助于促进团队合作、提高效率,便于后期的维护。

代码规范化可以为我们带来如下好处

  • 不用再担心看到别人奇奇怪怪的代码格式(有人喜欢一行平铺,有人喜欢层级嵌套)
  • 不用再担心在自动保存的时候触发自己编辑器中的格式化,导致CodeReview 时,出现上千行的格式改动,这真的是crazy。
  • 不用再去纠结自己的缩进是4字符,而同事的缩进是2字符。
  • 将团队开发成本前置,优化团队开发体验

。。。总之好处多多,哈哈。老图新用

看了本文之后,可以学习到

  • 如何在项目中集成eslintperttier保证代码质量
  • 如何在项目中配置EditorConfig来保证团队合作中编辑器配置同步
  • 如何在项目中配置husky + commitlint来对git提交进行校验
  • 我们为什么要配置这些内容

在团队合作中,我们开发人员常常会使用不同编辑器,并且大家对于编辑器中的配置往往有所差异,成员A的缩进是4字符,而成员B的缩进是2字符。那么应该如何去将规范团队成员的编辑器配置呢?

配置EditorConfig来规范编辑器的配置

什么是EditorConfig

EditorConfig致力于为各种编辑器和IDE处理同一项目的多个开发人员保持一致的编码样式。

editorconfig.org/

EditorConfig如何工作

打开文件时,EditorConfig 会在打开的文件的目录和每个父目录中查找名为 .editorconfig的文件。如果到达根文件路径或找到root=true的EditorConfig文件,则对 .editorconfig 文件的搜索将停止。

EditorConfig文件从上到下读取,找到的最新规则优先。匹配的 EditorConfig 部分的属性将按其读取顺序应用,因此较近文件中的属性优先。

因为editorConfig 是为了抹平编辑器之间的配置差异,那么我们就需要一个编辑器侧的同志,将我们的配置读取并设置到编辑器中。此处以VsCode 为例, 就是下面的家伙。

image.png 在下载好这个插件之后,我们就可以创建.editorconfig文件了,如下配置

# https://editorconfig.org

# 已经是顶层配置文件,不必继续向上搜索
root = true

[*]
# 编码字符集
charset = utf-8
# 缩进风格是空格
indent_style = space
# 一个缩进占用两个空格,因没有设置tab_with,一个Tab占用2列
indent_size = 2
# 换行符 lf
end_of_line = lf
# 文件以一个空白行结尾
insert_final_newline = true
# 去除行首的任意空白字符
trim_trailing_whitespace = true

[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

Editorconfig可配置的编码风格配置字段包括:

indent_style    设置缩进为 tab 或 space

tab_width       设置 tab 所占列数。默认是indent_size

indent_size     设置缩进所占列数,如果 indent_style 为 tab,则以 tab_width 值作为缩进宽度

end_of_line     设置换行符,值为lf、cr和crlf

charset         设置编码,值为latin1、utf-8、utf-8-bom、utf-16be和utf-16le,不建议使用utf-8-bom

trim_trailing_whitespace  设为 true 表示会去除行尾的空白字符

insert_final_newline      设为 true 表示使文件以一个空白行结尾

root     表示是最顶层的配置文件,设为 true 时,停止向上查找

详见 官方文档

这样,我们就可以控制 编辑器 的配置格式了

感谢 低调务实优秀中国好青年 群友 鲜榨柠檬气泡水 指出错误,❤️

在配置EditorConfig之后,我们就可以保障,团队成员在开发时,编辑器的配置都是项目中配置的格式,从而提升编码体验。

以上,我们配置了团队中编辑器的配置统一,但是我们在开发中,每个成员往往都有自己的编码风格,成员大佬A喜欢简单粗暴的一行中显示全部配置,而新世代成员B喜欢将配置进行平铺来直观的展示。那么,在团队开发的过程中,就会出现相互鄙夷的情况,导致项目风格一言难尽。我们可以配置 Prettier来规范团队开发中的代码风格。

配置Prettier来规范代码风格

Prettier 解决的问题

每位开发者的代码书写风格或多或少都有不同,比如一些作者喜欢加分号,一些作者认为基于 JS 引擎识别能力根本没有必要写分号。在 Prettier 之前,对于代码风格的争论似乎永无定论。统一规范便能终止争论,人们不用再纠结于如何设计代码样式,代码修改将集中于逻辑而非代码样式。 --- 稀土掘金 Curly_Brackets

借鉴一下,大佬文章放在文章末尾

什么是Prettier

多说无益,官方文档

Prettier is an opinionated code formatter with support

prettier 是一个自动格式化代码的工具,它会在我们保存代码时,帮助我们将代码格式化成我们规范的代码风格的样子。

Prettier应该如何使用

让我们先安装这个npm包

yarn add prettier --dev --exact

然后我们要创建一个prettier配置文件 .prettierrc

按照官网上的命令行使用,就可以快速创建一个

node --eval "fs.writeFileSync('.prettierrc','{}\n')"

以及一个prettier 忽略文件配置 .prettierignore

node --eval "fs.writeFileSync('.prettierignore','# Ignore artifacts:\nbuild\ncoverage\n')"

这样的话就会生成上述的两个配置文件

配置项

Prettier 提供如下配置,可按需查询选项在.prettierrc自行配置,详见官网

选取了部分较为常用的配置项,如下

{
  "tabWidth": 2,
  // tab缩进占用的列数
  "useTabs": true,
  // 缩进风格是否是Tab,默认是false,使用空格缩进
  "semi": true,
  // 是否在语句末尾添加分号
  "singleQuote": true,
  // 是否使用单引号
  "trailingComma": "all",
  // 是否在对象或数组最后添加逗号
  // 多行时是否结尾添加逗号
  // "es5" ES5中允许逗号的容器中添加逗号,比如 objects/arrays
  // "all" 尽可能添加逗号
  // "none" 不允许添加逗
  // 默认值是 "es5"
  "bracketSpacing": true,
  // 是否保留对象内侧两端的空格
  // true: { foo: bar }
  // false: {foo:bar}
  "bracketSameLine": false,
  // 将多行 HTML(HTML、JSX、Vue、Angular)元素的 > 放在最后一行的末尾,而不是单独放在下一行(不适用于自闭合元素)。
}

将这些选项配置好后,就可以运行指令来格式化文件了

yarn prettier . --write

在项目中,我们会在代码提交前进行代码格式化,在Git Hooks 的 pre-commit阶段执行 perttier --write

具体的我们将在后续进行讲解。

这时,我们保证了提交到git仓库的代码格式是统一的,但是我们日常开发中如何实现自动保存时安装项目中的代码风格进行格式化?

编辑器配置

这里以Vscode来举例,VS大法好,不接受反驳。

首先,我们需要在拓展程序中下载 Prettier这个拓展

在下载好之后,我们需要将Prettier设置为默认的格式化工具

点击设置Prettier为格式化程序便可。

记得也要同步开启vscode的保存时自动格式化的功能。

这样我们就可以实现在保存代码时自动进行prettier保存了。

这时,我们配置好了代码格式化和编辑器配置统一,但是有没有发现,我们其实没有办法去判断,团队成员中是否有人在代码里“下毒”。这时我们就需要配置Eslint。(生硬的转场,🤮)

配置Eslint来规范代码质量

什么是Eslint

Eslint 是一个根据方案识别并报告 ECMAScript/JavaScript 代码问题的工具,使用 espress将 JavaScript 代码解析成 抽象语法树(AST), 然后通过AST来静态分析我们的代码,从而给予我们两种提示

  1. 代码质量问题:使用方式有可能有问题(problematic patterns)
  2. 代码风格问题:风格不符合一定规则 (doesn’t adhere to certain style guidelines)

在计算机科学中,lint是一种工具的名称,它用来标记代码中,某些可疑的、不具结构性(可能造成bug)的语句。它是一种静态程序分析工具,最早适用于C语言,在UNIX平台上开发出来。后来它成为通用术语,可用于描述在任何一种编程语言中,用来标记代码中有疑义语句的工具。 -- by wikipedia

Eslint 可以干什么

帮助我们做静态语法分析,在代码执行之前发现错误。

  1. 帮助我们发现语法错误,如使用未声明变量、缺少右括号等等。
  2. 提示我们删除多余代码,如return 后面的语句、永远不会执行的else 分支等。
  3. 。。。等等
Eslint怎么使用

安装Eslint依赖

yarn add eslint -D

在安装好Eslint后,我们就需要初始化Eslint配置

npx eslint --init

这样在进行一系列的用户配置项选择后,就会生成一个eslint配置文件eslint.config.js

看上去最新版的eslint配置文件已经变更了, Eslint

这只是生成了最基本的Eslint配置,需要根据个人的使用,来进行加入,目前使用Vite创建的项目是自带Eslint

由于本文是为了讲解如何搭建一个项目整体的规范化,而不是讲Eslint如何使用,Eslint的具体配置,就不多加赘述了。后续找机会单独出一期

当我们集成了Eslint之后,Eslint会根据我们配置的规则 & 规则集来对我们的代码进行分析。

运行 以下脚本命令 就可以对需要校验的文件进行Eslint校验

yarn eslint

这样我们就实现了对代码质量的把控,但是有聪明的朋友会发现,Eslint 也可以实现代码风格检查,那是否可以只用到Eslint呢?

Eslint是否可以代替Prettier?

哈哈,既然都这样说了,那肯定是不行,起码目前不行。Eslint 中的 Formatting rules 并非都提供了 fixer,其次 Eslint 着重于 JS/TS, 无法兼顾CSS、Markdown 的代码风格。

那如何解决两者职责重叠部分的冲突,避免两者重叠部分导致的冲突?

解决Eslint与Prettier的冲突

这里是官方给出的解决方案:解决方案

  1. 使用 eslint-config-prettier

解决方案为: 将Prettier的规则复写进Eslint中,并对原本eslint中的格式配置进行覆盖,这样就可以做到eslint的格式化检查和Prettier的格式化行为统一。

  1. 使用 eslint-plugin-prettier

将 prettier 作为 eslint 的规则运行,并将差异作为单独的Eslint问题报告。

我们通常需要同时安装上述两个包来实现Eslint 和 Prettier 的集成,来同时享受到Eslint的代码检查功能和Prettier的代码格式化功能,并确保二者之间的规则一致性。

首先,我们来下载这两者的依赖

yarn add -D eslint-plugin-prettier eslint-config-prettier

然后对于8x版本及之前的Eslint版本,可以在.eslintrc*中设置

{
  "extends": ["plugin:prettier/recommended"]
}

对于新版本的Eslint,需要在eslint.config.js中配置

const eslintPluginPrettierRecommended = require('eslint-plugin-prettier/recommended');

module.exports = [
  // Any other config imports go at the top
  eslintPluginPrettierRecommended,
];

具体配置,详见 eslint-plugin-prettier

这样我们就解决了Eslint和Prettier的冲突。那么我们就可以快乐的编码了。

于是小金开始了快乐的团队开发,在某天,他发现自己拉取的代码中出现了明显不是团队风格的代码,于是他溯源找到了老金,原来是老金换了电脑,导致没有vscode自动保存!!!所以,大家有没有发现,我们缺少了自动进行格式化校验的动作。

但是我们总不能要求团队成员在每次提交代码前都运行多次这条指令来对文件进行校验吧,总不能每次都检查全部文件吧。

那么我们需要在一个特定的时机,去对我们的代码进行校验和修正,这时我们就需要用到 Git Hooks

配置Git Hooks来实现代码规范自动化

Git钩子是每次在Git存储库中发生特定事件时自动运行的脚本。它们允许开发者自定义Git的内部行为,并在开发生命周期的关键点触发可自定义的操作。

Git 钩子分为客户端钩子和服务器端钩子,这里我们重点列举客户端钩子中常见的几个。具体请看,Git Book

pre-commit: 在键入提交信息前运行(这里是指程序写入提交信息前)

prepare-commit-msg: 在启动提交信息编辑器之前,默认信息被创建之后运行

commit-msg: 接收唯一参数-> 包含消息的文件名,在这里可以对用户的提交信息进行校验,判断是否符合某种模版。

post-commit:commit-msg钩子之后立即被调用。它无法更改git commit操作的结果,因此它主要用于通知目的。

所有的pre-钩子都允许你改变即将发生的操作,而post-钩子仅用于通知。

如上所说,我们完全可以在 pre-commit期间去校验我们的代码是否符合规范,于是我们就想到了 husky

什么是Husky

使现代的原生 Git 钩子变得简单 -- Husky

在提交或推送时,自动化 检查提交信息检查代码运行测试

如何使用Husky

首先安装Husky依赖, 并对Husky 进行初始化

// 安装 husky 依赖
yarn add --dev husky
// 对 husky 进行初始化, 因为这里yarn的初始化比较特殊,所以先用npm进行初始化
npx husky init
// 配置prepare命令,实现在其他用户执行npm install 时自动执行 husky install

在初始化之后,我们就可以看见,项目目录中新增了 .husky目录,在里面我们可以进行对应的Git钩子操作。

目的: 在pre-commit钩子执行时,对项目代码进行格式化 并且 对代码质量进行校验。

那我们完全可以在 pre-commit 钩子中执行 yarn lint脚本

但是这样会对所有Eslint中未忽略的文件进行格式化校验。这样的话,可能会导致非本次提交的代码被格式化,导致多余的更改被添加。这时我们就需要用到 lint-staged

什么是 lint-staged

Run linters against staged git files and don't let 💩 slip into your code base!

针对暂存的 git 文件运行 linter,不要让它💩溜进您的代码库!

lint-staged 会对在暂存区的代码执行指定的指令

如何使用 lint-staged

首先安装依赖

yarn add -D lint-staged

在package.json文件中添加对应配置

"scripts": {
    // 新增这一行
    "lint-staged": "lint-staged",
    ...
},
// 配置lint-staged的具体任务
// 这样配置之后,在每次本地commit之前,都会去校验提交内,如果有不符合eslint规则的代码,就会去执行
// eslint --fix 尝试自动修复,修复成功后会把修复后的代码提交,如果失败,会提示错误,
// 手动修复后才允许提交代码
"lint-staged": {
  "*.tsx|*.ts|*.js": [
    "eslint --fix"
  ]
},

注意

lint-stagedv10之后,git add部分是自动的,不需要包含在配置中

如果你在v10版本中配置了git add

"lint-staged": {
  "*.tsx|*.ts|*.js": [
    "eslint --fix",
    "git add"
  ]
},

那么会报一个警告

关于这个问题的issue

在 husky 的pre-commit脚本中配置要执行的指令

这时,我们尝试提交一个带有 debugger 的文件, 这时 Eslint 就会检测到对应的文件

这里做个对比看一下

能明显看到在提交commit时,只校验了暂存区中的文件。 并且 eslint --fix 帮我们自动修复了 在App.tsx文件中的双引号不规范的问题。

这时我们完成了在提交前进行eslint校验,但是我们还是没有对代码风格进行格式化,该如何做呢?这个时候就要用到 pretty-quick

什么是 pretty-quick

pretty-quick 会在我们已更改的文件上运行 prettier 格式化。pretty-quick

如何使用 pretty-quick

首先下载依赖

# yarn
yarn add -D prettier pretty-quick

然后将其配置在我们的 pre-commit

这里的 --staged 指令是为了将格式化范围限制在git的暂存区

当我们进行一次提交,我们就会发现,在提交代码时会对我们的代码进行格式化。

再延续着讲一下如何在 commit-msg阶段对提交信息进行校验

配置Commitlint 来规范提交信息

什么是规范的提交信息

在每次 git commit 时,我们都需要写 commit message,在日常开发中,为了使这条信息既简短,又能表达更多的内容,社区内形成了很多规范,大致如下:

  1. feat: 新特性
  2. fix: 修复 bug
  3. style: 关于代码风格的修改(注意不是 CSS style)
  4. refactor: 重构
  5. test: 测试相关的代码
  6. docs: 文档相关
  7. chore: 构建过程或者辅助工具的变动
commitlint如何使用

首先去安装 commitlint 依赖

// 其中 config-conventional 是一个社区中的规范
yarn add --dev @commitlint/{cli,config-conventional}

在安装之后,我们就需要进行配置了,这里使用官网推荐的独立配置文件

echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

接着需要在项目中创建commit-msg脚本, 并在package.json中配置commitlint脚本命令

在husky中添加 hook 与创建文件一样简单。可以通过你喜欢的编辑器、脚本或 echo 命令来实现。例如,在 Linux/macOS 中:

npm pkg set scripts.commitlint="commitlint --edit"
echo "npm run commitlint ${1}" > .husky/commit-msg

尝试进行错误提交, 发现我们简陋的提交已经被检测了出来。

至于是否要配置 commitlint/prompt-cli或者commitizen来便捷团队成功git提交,那就是各位看官需要考虑的事情了。

题外话

做一件事,最难的在开始,其次是进行中,在编写本文查资料时,突然发现有大哥已经写出一个很详尽的文章了,就开始怀疑,自己是否要继续写下去,最后还是坚持写了下来,一千个人就有一千个哈利波特,每个人对一件事情都有自己的看法,希望我的文章也能帮到大家。

在写本文之前,曾对项目中规范化配置一知半解,只知道 prettier + eslint + husky 梭哈,具体细节也不太清晰,故写此文进行梳理。

本文结束,但是笔耕不辍,未来待续!

祝诸君武运昌隆!

参考资料

写的确实棒

不知名大佬的知识库

全面梳理代码规范化:EditorConfig + Prettier + ESLint

深入理解 ESLint

在项目中使用 ESLint 与 Prettier 以及 EditorConfig