【前端劝退指南】前端工程化 —— 约束规范

1,355 阅读5分钟

前言

前端工程化中,约束规范是很重要的一个环节,不能十个工程师,十种代码风格,这无疑会增加团队对代码的维护负担以及心理压力,特别碰到强迫症的同学,一看跟我风格不一样,直接全部改掉,剩下其他同学在风中凌乱。

image.png

大纲

本文涉及到的约束规范主要包括:

  • ESLint
  • IDE
  • Git Hooks
  • 总结
  • package.json 文件

ESLint

ESLint 大家都不陌生,它可以查找并修复 JavaScript 代码中的问题

特点一:发现问题

ESLint 静态分析你的代码以发现问题。

特点二:自动修复

ESLint 发现的许多问题都可以自动修复。ESLint 修复是语法感知的,因此你不会遇到传统查找和替换算法引入的错误。

特点三:定制

预处理代码,使用自定义解析器,并编写与 ESLint 的内置规则一起工作的自己的规则。你可以自定义 ESLint 以完全按照你的项目需要的方式工作。

如何配置

npm install eslint --save-dev

规则需要统一集中配置,ESLint 会默认读取配置文件 .eslintrc 来解析,而规则集在 rules 中进行配置

{
    "rules": {
        // 函数括号前面不加空格
        'space-before-function-paren': ['error', 'never'],
        // 关闭要求 require() 出现在顶层模块作用域中
        'global-require': 0,
        // 关闭关闭类方法中必须使用this
        'class-methods-use-this': 0,
    }
}

rules 的配置参考文档和最佳实践可以参考下文:eslint-rules

那 eslint 有这么多规则,我们需要一个一个去研究然后一个一个去配置吗?

当然不用啦,github 上已经有大神总结了一套优雅的规则

part one —— ctrl C + ctrl V

官方提供的简单且实用的配置:eslint-recommended

part two —— extends

优秀团队 airbnb(爱彼迎)设定了一套约束特别强的规范:airbnb/javascript

当配置 .eslintrc 时,使用 config.extends 将会继承已有的 .eslintrc 配置文件,配置时可省略 eslint-config- 前缀

比如使用 airbnb-base,我们将基于 eslint-config-airbnb-base 这份 eslint 配置文件,再补充自己的配置文件

{
  "extends": ["airbnb-base"],
  "rules": {
    // 函数括号前面不加空格
    'space-before-function-paren': ['error', 'never'],
    // 关闭要求 require() 出现在顶层模块作用域中
    'global-require': 0,
    // 关闭关闭类方法中必须使用this
    'class-methods-use-this': 0,
  }
}

vue 项目可以用以下规则: npm install --save-dev eslint-config-vue

{
    "extends": "vue"
}

假如是 umi 项目,也可以使用包含 prettier,eslint,stylelint 的配置文件合集 umi-fabric

npm i @umijs/fabric --save-dev

{
    "extends": [require.resolve('@umijs/fabric/dist/eslint')]
}

IDE

编辑器以 vscode 为例

我们需要安装一个插件:eslint

image.png

打开配置

image.png

切换到 JSON 配置信息

image.png

相关配置信息可以参考如下链接:microsoft-vscode-eslint

推荐先开启下面两个配置:

{
    "eslint.format.enable": true, // 用例格式化代码
    "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true // 保存代码时自动修复
    },
}

Git Hooks

有同学看到这就要说了,这也太复杂了,我不想搞呀,能不能简单点,敲代码的方式简单点,我直接提交代码了,不整这些花里胡哨的。

但是很快他就傻眼了,他提交不了呀,被拦截了。

拦截他的大哥有:

pre-commit

这是 git 在你键入提交信息前运行的钩子。它用于检查即将提交的快照,例如,检查是否有所遗漏,确保测试运行,以及核查代码。

在项目目录下,我们可以看到 git 所有的 hook

image.png

有这位大哥还不行,太单薄了,还得有左青龙护法 —— husky

husky(不是狗狗哈士奇🐶)

当你提交或推送时,你可以使用它来 lint 提交消息、运行测试、lint 代码等(所有的hooks)

// 提示:在我们前面已经把 eslint 配置好的前提下,执行如下操作

// 下载 husky 4.x 版本
npm install husky@4.2.5 --save-dev

// 配置 package.json
// 添加 scripts
"scripts": {
    "lint": "eslint . --cache"
},
// 添加 husky 配置
"husky": {
    "hooks": {
      "pre-commit": "npm run lint"
    }
},

现在创建一个 demo.js 并写上如下内容

// TODO
const a = 3

如果你前面 eslint 设置成功的话,将看到如下提示

image.png 此时执行 git commit -m 'test' 提交代码会发现提交失败,并且有如下提示:

image.png 说明我们通过 pre-commit 钩子在提交代码前做 eslint 校验成功了 🎉🎉🎉

但是这样存在一个问题,假如我们通过某种方式绕过了 git hooks 的校验(后面会讲到)讲有错误的代码提交上去了,我们下次再做上述操作时,eslint 会扫描所有代码,速度会比较慢

image.png

这个时候就得请出我们的右白虎护法 —— lint-staged

lint-staged

该项目包含一个脚本,该脚本将运行任意 shell 任务,并将暂存文件列表作为参数,由指定的 glob 模式过滤。

npm i lint-staged --save-dev

类似如下配置:

"scripts": {
    "lint": "eslint . --cache", // 删除,可以不用了
    "lint-staged:js": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx "
},
"husky": {
    "hooks": {
      "pre-commit": "lint-staged" // git hook 改成执行 lint-staged
    }
  },
"lint-staged": {
    "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js"
  }

我们再次提交代码试一下,可以看到,现在只提示了在暂存区代码的错误

image.png

更优雅

commit-msg 检查 —— commitlint

检查 git commit -m 'xxx' 的 message 是否符合规范

// 安装 @commitlint/cli @commitlint/config-conventional
npm install @commitlint/cli @commitlint/config-conventional -D

// 采用基于 vue-cli3 的代码提交检查规范 vue-cli-plugin-commitlint
npm install vue-cli-plugin-commitlint -D

可以在 .commitlintrc.js 中定义配置

module.exports = {
  extends: ['./node_modules/vue-cli-plugin-commitlint/lib/lint'],
}

配合 husky 使用

"husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS"
    }
  }

测试一下 git commit -m 'test' 会发现报如下错误

image.png 正确姿势如下(具体规范,可参考:what-is-commitlint)

image.png

更更优雅一点

优雅生成 message —— commitizen

当使用 Commitizen 提交时,系统会提示你在提交时填写所有必需的提交字段。比如上面使用 commitlint 时,提交完之后才提示需要加对应的规范钩子。

使用 Commitizen无需再等待 git commit 钩子运行并拒绝你的提交。不再需要通过 CONTRIBUTING.md 来查找首选格式。 获取有关提交消息格式的即时反馈,并提示输入必填字段。

npm install -g commitizen

// package.json
"scripts": {
    "cz": "git add . && git cz"
}
"config": {
    "commitizen": {
      "path": "./node_modules/vue-cli-plugin-commitlint/lib/cz"
    }
  }

安装成功后,Commitizen 会生成 git cz 命令,用来替代 git commit

执行 npm run cz 出现如下提示

image.png 要解决此错误,我们再需要安装一个 right-pad

npm install right-pad -D

好了,再次执行 npm run cz,就会出现非常友好的 message 了

image.png

更更更优雅一点

优雅生成 change log —— 提交版本记录

npm install conventional-changelog-cli -D

// package.json
"scripts": {
    "cz": "npm run log && git add . && git cz"
}

再次执行 npm run cz,就会生成一个 CHANGELOG.md 文件随着本次代码提交一起提交上去

image.png

// CHANGELOG.md
# 1.0.0 (2021-12-05)

### 🌟 新功能
范围|描述|commitId
--|--|--
 - | test | [4ffaad2](https://gitee.com/HY0606/git-hook-demo/commits/4ffaad2)


范围|描述|commitId
--|--|--
 - | test | [05ef22a](https://gitee.com/HY0606/git-hook-demo/commits/05ef22a)
 - | test | [0191aec](https://gitee.com/HY0606/git-hook-demo/commits/0191aec)
 - | Initial commit | [56ff86a](https://gitee.com/HY0606/git-hook-demo/commits/56ff86a)

vscode 可以下载 Markdown Preview Enhanced 插件,查看 md 文件预览模式

image.png

总结

至此,一套提交代码规范,并且生成 CHANGELOG 的配置就算完成了,这样可以极大的帮助我们统一代码规范,减少多人协作的沟通的成本,让大家都能早点下班 🐶

希望对大家有所帮助,如果哪里写错了,请大家多多指出。

image.png

package.json

// package.json
{
  "name": "git-hook-demo",
  "version": "1.0.0",
  "description": "#### Description 实验 husky 管理 git hook",
  "main": "demo.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "lint-staged:js": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx ",
    "commit": "git cz",
    "log": "conventional-changelog --config ./node_modules/vue-cli-plugin-commitlint/lib/log -i CHANGELOG.md -s -r 0",
    "cz": "npm run log && git add . && git cz"
  },
  "repository": {
    "type": "git",
    "url": "https://gitee.com/HY0606/git-hook-demo.git"
  },
  "author": "",
  "license": "ISC",
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged",
      "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS"
    }
  },
  "lint-staged": {
    "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js"
  },
  "dependencies": {
    "eslint": "^8.3.0",
    "husky": "^4.2.5"
  },
  "devDependencies": {
    "@commitlint/cli": "^15.0.0",
    "@commitlint/config-conventional": "^15.0.0",
    "commitizen": "^4.2.4",
    "conventional-changelog-cli": "^2.1.1",
    "lint-staged": "^12.1.2",
    "right-pad": "^1.0.1",
    "vue-cli-plugin-commitlint": "^1.0.12"
  },
  "config": {
    "commitizen": {
      "path": "./node_modules/vue-cli-plugin-commitlint/lib/cz"
    }
  }
}