代码规范
是 前端工程化
落地的基石,用于约束 编码规范
和 编码风格
,它的好处是:
- 强制规范代码风格统一,保持一样的编码习惯
- 增加代码的可维护性和可接入性,即使有新成员的加入也能快速适应项目的架构与需求
- 保障项目的整体质量,可减少无用代码、重复代码、错误代码和
BUG
代码的产生几率
我们通过配置代码校验工具(简称 Lint
)来检测代码中的错误和漏洞,再根据其提供的修复方案格式化出正确代码。实现保存代码时一键校验,统一项目的编码规范和编码风格
项目最终配置示例链接 🔗 在本文末尾
Lint
Lint
其实就是编辑器中运行的一个 脚本进程
,它会将代码解析为 AST 抽象语法树
🌲,再通过遍历语法树并通过预设规则去进行判断和改动,再将更新后的语法树转换为(尽量)规范化的代码
配置 eslint & prettier
- 安装
pnpm i eslint prettier @typescript-eslint/parser -D
pnpm i @typescript-eslint/eslint-plugin -D
- 可以在
vscode
插件中安装Prettier
和Eslint
插件,在设置中开启保存文件则进行格式化;也可配置scripts
命令(这会检测你指定目录的所有文件,当然会比较耗时)。另外可结合lint-staged
只对commited
后的文件进行格式化重写(见下面的pre-commit
git-hooks
触发)
{
"scripts": {
"format": "prettier --write src/**/*/*.{js,jsx,ts,tsx}",
"lint": "eslint src --ext .js,.jsx,.ts,.tsx --fix"
}
}
- 通过配置文件声明代码格式化的格式
// .eslintrc.js 文件,常规配置方案
module.exports = {
env: {
browser: true,
es2021: true
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended'
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module'
},
plugins: ['@typescript-eslint'],
rules: {}
}
// .pretterrc 文件
semi: false // 不用 ; 结尾
singleQuote: true // 单引号
printWidth: 80 // 文本超过 80 换行
trailingComma: 'none' // 尾逗号
arrowParens: 'avoid' // 箭头函数参数只有一个时是否要有小括号(avoid - 省略)
// 其他更多配置
bracketSpacing: true, // 在对象,数组括号与文字之间加空格 "{ foo: bar }"
disableLanguages: ["vue"], // 不格式化vue文件,vue文件的格式化单独设置
endOfLine: "auto", // 结尾是 \n \r \n\r auto
eslintIntegration: false, //不让prettier使用eslint的代码格式进行校验
htmlWhitespaceSensitivity: "ignore",
ignorePath: ".prettierignore", // 不使用prettier格式化的文件填写在项目的.prettierignore文件中
jsxBracketSameLine: true, // 在jsx中把'>' 是否单独放一行
jsxSingleQuote: true, // 在jsx中使用单引号代替双引号
parser: "babylon", // 格式化的解析器,默认是babylon
requireConfig: false, // Require a 'prettierconfig' to format prettier
stylelintIntegration: false, //不让prettier使用stylelint的代码格式进行校验
trailingComma: "es5", // 在对象或数组最后一个元素后面是否加逗号(在ES5中加尾逗号)
tslintIntegration: false // 不让prettier使用tslint的代码格式进行校验
Commit 规范
我们在使用 Git
托管代码时,规范化的 Commit Message
可以帮助大家直观清晰地理解每次修改的内容,不仅能帮助别人 Review
,还可以有效地输出 ChangeLog
。那么要想前端工程化项目更易于维护,最好有一套 Git
提交说明的 规范化模板
目前最受开发人员肯定的规范是前端框架 Angular
提出的 Angular提交信息规范 🔗,包含 Header
(必填)、Body
和 Footer
三个部分的内容,提交格式如下:
<type>(<scope>): <subject>
# 空行
<body>
# 空行
<footer>
-
Header
作一行书写,包含type
,scope
,subject
三个字段的内容-
type
:用于说明 commit 提交类型(必填,常用类型如下)feat
:新增功能fix
:Bug修复docs
:文档更新ci
:脚本更新,修改了 CI 配置文件或脚本pref
:性能优化,提高性能的代码更改build
:更新构建,构建系统或者外部依赖项进行了修改、更新test
:新增测试,增加确实的测试或者矫正已存在的测试refactor
:代码重构,非新增功能也非修复缺陷chore
:事务变动,改动其他不影响代码的事务revert
:代码回滚,撤销某次代码提交merge
:分支合并,合并分支代码到其他分支style
:格式变动,不影响代码逻辑release
:版本发布
-
scope
:用于说明 commit 的影响范围(选填)(比如按下面这些划分方案填写)- 按功能划分(如:数据层 -
Data
、视图层 -View
和 控制层 -Control
) - 按交互层划分(如:组件 -
Component
、布局 -Layout
、流程 -Flow
、视图 -View
和 页面 -Page
) - 按改动文件划分(如:某个文件 -
Button.tsx
,全部改动 -*
)
- 按功能划分(如:数据层 -
-
subject
:用于说明 commit 的细节描述(选填)。以精炼简洁的文字(中文还是英文就看各自规定了,一般推荐使用英文)说明提交的改动,比如可以遵循这些规则:- 以动词开头(如:
update
,更新
) - 使用第一人称现在时
- 首字母无需大写,重点区分的(如某组件)首字母无需大写
- 不以句号(
.
/。
)结尾
- 以动词开头(如:
commit
信息示例:feat(Component): add Layout component feat(Button.tsx): change the default size of the button fix(EmitEvent): handle event on blur (closes #28)
-
-
Body
部分可书写多行,对subject
做更详尽的描述,内容应包括改动动机
与改动前后对比
-
Footer
部分只适用两种情况,分别是不兼容变动
与问题关闭
- 不兼容变动:当前代码与上一版本不兼容,则以
BREAKING CHANGE
开头,关联变动描述、变动理由和迁移方法 - 问题关闭:当前代码已修复某些
Issue
,则以Closes
开头,关联目标Issue
- 不兼容变动:当前代码与上一版本不兼容,则以
方案一:husky
+commitlint
-
安装
pnpm i husky @commitlint/cli @commitlint/config-conventional -D
-
初始化
husky
,创建.husky
文件夹(本质就是创建要触发的git-hooks
)npx husky install # 安装 git hooks,创建 .husky 目录 # 结果:husky - Git hooks installed # 执行 npx husky-init # 它会在 package.json 文件的 scripts 字段中 # 创建 "prepare": "husky install" 命令 # 同时在 .husky 目录下创建 pre-commit 文件 # 结果:husky - created .husky/pre-commit
-
在
.husky
目录下添加commit-msg
hooknpx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
# 结果:husky - created .husky/commit-msg # .husky/commit-msg 文件内容: #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" npx --no -- commitlint --edit ""
-
在
package.json
配置git-hooks
{ "husky": { "hooks": { /* commit 信息提交前会执行此 script,若未配置此命令,将会跳过 */ "pre-commit": "npm run test", "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS" } } }
-
创建
commitlint.config.js
文件夹module.exports = { extends: ['@commitlint/config-conventional'] }
至此,我们基本配好了 git commit
命令会执行默认的检测方案。当然,这里我并未深入测试更多,测试结果如下(未通过规范时则无法完成 commit):
# 下面的 'test......' 就是 index.js 中写的用来测试的 console.log
➡️ git commit -m "t"
> xxx@0.0.0 test
> node index.js # 配置的 test 命令
test......
⧗ input: t
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]
✖ found 2 problems, 0 warnings
ⓘ Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint
husky - commit-msg hook exited with code 1 (error)
方案二:yorkie
+verifyCommits.js
(实践发现并不能触发 gitHooks)
结合上面的代码规范 Lint
,我们可以在 pre-commit
hook 中进行代码格式化,commit-msg
hook 我们可以执行我们自己定义的 js 文件去校验 commit
信息是否符合我们定义的 commit 规范
-
安装
pnpm i yorkie lint-staged chalk eslint prettier @typescript-eslint/parser -D
yorkie
:EvanYou
forkhusky
的一个npm
包(它不兼容husky
)lint-staged
:它仅是一个文件过滤器,这里的 staged 是与 Git 中的概念一致的,过滤出Git
代码暂存区的代码(committed
的代码)chalk
:一个多彩的log
记录工具eslint
,prettier
:上面的Lint
工具@typescript-eslint/parser
:用于解析格式化typescript
代码
-
配置
hooks
(package.json
){ "gitHooks": { /* 触发格式化 */ "pre-commit": "lint-staged", /* 我们自定义的校验 commit 信息的 js 文件 */ "commit-msg": "node scripts/verifyCommit.js" }, "lint-staged": { "*.js": [ "prettier --write" /* 结合 .prettierrc 文件声明格式 */ ], "*.ts?(x)": [ "eslint", /* 结合 .eslintrc.js 文件声明格式 */ "prettier --parser=typescript --write" ] } }
-
自定义
verifyCommits.js
const { bgRed, red, green } = require('chalk') const msgPath = process.env.GIT_PARAMS const msg = require('fs') .readFileSync(msgPath, 'utf-8') .trim() /* commit 信息规则, */ const commitRE = /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/ if (!commitRE.test(msg)) { console.log() console.error( ` ${bgRed.white(' ERROR ')} ${red( `invalid commit message format.` )}\n\n` + red( ` Proper commit message format is required for automated changelog generation. Examples:\n\n` ) + ` ${green(`feat(compiler): add 'comments' option`)}\n` + ` ${green( `fix(Input.tsx): handle events on blur (close #28)` )}\n\n` + red(` See .github/commit-convention.md for more details.\n`) ) process.exit(1) }
至此,已经完成 yorkie 配置,但实际测试提交 commit 时,并不能触发 pre-commit
和 commit-msg
hook,可能是我哪里使用的姿势不对吧!(故放弃)
方案三:结合 husky 和自定义 verifyCommits.js
-
安装
pnpm i husky lint-staged eslint prettier chalk -D # 太长,分两行书写,下面的是对 ts 文件格式化的插件 pnpm i @typescript-eslint/parser @typescript-eslint/eslint-plugin -D
npx husky install # 安装 .husky 目录 npx husky-init # 创建 pre-commit hook
-
修改
.husky/pre-commit
文件:#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" # npm test # 这句删掉,改为下面这行,进行代码格式化检测 npx lint-staged
-
添加
commit-msg
hook# scripts/verifyCommits.js 即为我们自定义的校验文件 npx husky add .husky/commit-msg 'node scripts/verifyCommits.js "$1"'
⚠️:
$1
必须在.husky/commit-msg
文件中写上(在我们使用git commit -m "[msg]"
时,会传递给$1
参数),否则我们执行自定义校验commit
文件时是无法拿到commit 信息
的(当时花费好长时间去踩这个问题点),文件内容如下:#!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" node scripts/verifyCommits.js "$1"
-
创建
scripts/verifyCommits.js
文件:// 注意:用于提示信息的 chalk 可能需要安装 4.1.0 版 // 5.1.0 版是 ES Module 模块化方案,无法在 node 中直接运行会报错 const chalk = require('chalk') // const msgPath = process.env.GIT_PARAMS // 此为 undefined 拿不到 msg 信息 // process.env 对象中没有任何 commit 信息,process.argv 中本来也没有 const msgPath = process.argv[2] // 上面 $1 必填,这里才能拿到本次的 CommitMsg const msg = require('fs').readFileSync(msgPath, 'utf-8').trim() console.log() // 空行,下面打印提示信息 console.log(chalk.bgBlueBright.white('Commit Msg: '), msg) console.log() // 打印提示信息后空行 const commitRE = /^(revert: )?(feat|fix|docs|dx|style|refactor|perf|test|workflow|build|ci|chore|types|wip|release)(\(.+\))?: .{1,50}/ if (!commitRE.test(msg)) { console.log() console.error( ` ${chalk.bgRed.white(' ERROR ')} ${chalk.red( `invalid commit message format.` )}\n\n` + chalk.red( ` Proper commit message format is required for automated changelog generation. Examples:\n\n` ) + ` ${chalk.green(`feat(compiler): add 'comments' option`)}\n` + ` ${chalk.green( `fix(input): handle events on blur (close #28)` )}\n\n` + chalk.red(` See .github/commit-convention.md for more details.\n`) ) process.exit(1) } // 当然还可以做些其他的事,这里毕竟运行在 node 环境,随你处理
-
配置
package.json
文件内容(实际上这里配不配都不影响,实际执行的依旧是.husky
目录下的 hook 文件,为了在package.json
文件中直观展示,我们将其同步){ /* husky hooks 不配也不影响 */ "husky": { "hooks": { "pre-commit": "lint-staged", // 执行下面的 格式化 "commit-msg": "node scripts/verifyCommits.js" } }, /* lint-staged 必须配置 */ "lint-staged": { "*.js": [ "prettier --write" /* 结合 .prettierrc 文件声明格式 */ ], "*.ts?(x)": [ "eslint", /* 结合 .eslintrc.js 文件声明格式 */ "prettier --parser=typescript --write" ] } }
-
创建
.eslintrc.js
文件和.pretterrc
文件中写上// .eslintrc.js 文件 module.exports = { env: { browser: true, es2021: true }, extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], parser: '@typescript-eslint/parser', parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, plugins: ['@typescript-eslint'], rules: {} }
// .pretterrc 文件 semi: false singleQuote: true printWidth: 80 trailingComma: 'none' arrowParens: 'avoid'
配置完毕,我们试试吧
➡️ git commit -m "tes: 错误示例 🙅<200d>♂️"
✔ Preparing lint-staged...
✔ Running tasks for staged files...
✔ Applying modifications from tasks...
✔ Cleaning up temporary files...
Commit Msg: tes: 错误示例 🙅♂️
ERROR invalid commit message format.
Proper commit message format is required for automated changelog generation. Examples:
feat(compiler): add 'comments' option
fix(input): handle events on blur (close #28)
See .github/commit-convention.md for more details.
husky - commit-msg hook exited with code 1 (error)
当然,整体来说也只是一个推荐性的规范方案,commit
同样可以通过 -n
或者是 -no-verify
直接绕开 commit
检测
添加 ChangeLog
- 安装
pnpm i conventional-changelog-cli -D
- 配置
scripts
(packages.json
)
{
"scripts": {
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s"
}
}
conventional-changelog-cli
不会覆盖任何以前的变更日志。 新增的日志基于自上一个 commit 的 "Feature"
, "Fix"
, "Performance Improvement"
或 "Breaking Changes"
基于此的示例配置项目:Github: sure-lint