前端codeLint-- 为项目集成ESLint、StyleLint、commitLint实战和原理

导读

Code Lint是前端工程化中的一个重要环节(what is code lint?),它可以帮助我们在部署代码到生产环境之前及时发现错误并纠正它们,也可以规范我们的编码习惯,让团队的代码风格保持统一。

Code Lint的工作原理是借助一些lint工具对代码进行静态分析,并在合适的时机触发校验,提示错误。

Note:本文可能无法覆盖所有知识点,若有知识盲区请主动查阅补齐,也可以在文章下方留言交流。

一、都有哪些Lint?

随着nodejs和前端工程化的发展,前端圈内产出了很多成熟的Lint工具,主要包括:

  • eslint 规范并校验 ECMAScript/JavaScript code的编写
  • tslint 规范并校验 TypeScript code的编写
  • stylelint 规范并校验css/scss/less code的编写
  • commitlint 负责校验commit msg是否符合规范
  • prettierbeautifyjs 统一代码排版格式

除此之外,我们还需要一些辅助的工具:

  • husky 能够监听git hooks的nodejs包,让nodejs开发者处理git hooks任务变得更加容易
  • lint-staged 可以将git“已暂存(staged)”的文件作为参数传入你要执行的shell script之中

读到此处,你可能对这些工具的作用和用法仍然心存疑惑,不过没关系,大家暂且只需要知道我们将用这些工具对我们的代码进行各环节的严格的校验即可,接下来让我们深入了解它们。

二、集成commit lint

相信大家对Git并不陌生,不知大家是否有过这种经历,自己提交git commit msg自己却看不懂。在小的团队里,可能我们更注重的是业务产出,并不在乎这些细节。随着团队的壮大,commit msg规范化至关重要,他意味着我们是否清楚自己和同事对代码干了什么,在代码排错、回滚甚至是甩锅时起到了关键性作用。

本着“工具比人更可靠”的原则,我们期望通过在项目中集成一些工具,从而实现在执行git commit -m 'msg'时能够自动的对msg内容进行校验,无需额外执行其他命令,huskycommitlint恰好能解决我们这个痛点。

2.1、理解git hooks 和 husky

在正式集成commitlint之前,先要介绍一下git hooks, 顾名思义hooks为“钩子”之意,它是“发布订阅模式”的一种实现,和前端中的DOM事件(click、hover等)相似,Git也预先定义了一些“事件钩子”如“commit-msg”、“pre-commit”等,当我们执行对应的Git操作时会触发它们,从而通知订阅该事件的shell script文件处理我们要进行的任务,这些shell脚本文件存放在项目根目录下的.git/hooks 目录中,如图所示:


image

我们可以通过编写这些shell script文件定制我们的校验任务,但前端工程师大多对linux/windows shell并不擅长,这和我们平时的工作重心有关, 因此我们通过编写git hooks脚本来优化前端工作流的这条道路十分艰难。Nodejs改变了这一切,它让JavaScript拥有了控制“操作系统”的能力,你只需要安装nodejs包husky,它会帮我们自动生成.git/hooks目录下的shell script,我们便可以很轻松的使用更熟悉的Nodejs处理git hooks任务,而无需关注shell script的实现细节。

执行下面命令, 在开发环境中安装husky,如下所示:

npm install husky --save-dev

在项目根目录下package.json文件中添加如下配置,并在hooks字段下添加git hooks监听任务配置, 如下:

// 这是NPM原生支持的脚本执行定义,当执行“npm run 脚本名”时执行
"scripts": {
    "test": "node test.js"
},
// 这是husky扩展的脚本执行的定义方式,当对应git hooks触发时执行
"husky": {
    "hooks": {
      // 可以执行一个js文件,将控制权转移给我们更熟悉的nodejs
      "pre-commit": "node heihei.js", 
      // 也可以调用其他脚本或者执行一段原生shell命令
      "commit-msg": "npm run test && echo succeed" 
    }
}

上面的配置只作为测试例子之用,无需真正集成到项目中,大家可以先写一个小demo尝试一下,加深一下对git hookshusky的理解。

2.2、安装配置commitlint

当然不要忘记我们今天的主角commitlint,我们需要利用它的cli(command-line interface)能力,配置一套属于我们自己的git commit msg 校验规则, 首先安装 @commitlint/cli@commitlint/config-conventional ,如下:

npm install @commitlint/cli --save-dev  
npm install @commitlint/config-conventional --save-dev
  • @commitlint/cli 是commitlint提供的命令行工具,安装后会将cli脚本放置在./node_modules/.bin/目录下
  • @commitlint/config-conventional是社区中一些共享的配置,我们可以扩展这些配置,也可以不安装这个包自定义配置

接下来是初始化@commitlint/cli的配置文件,在项目根目录创建名为commitlint.config.js的文件,代码如下:

/**
* feature:新功能
* update:更新某功能
* fixbug:修补某功能的bug
* refactor:重构某个功能
* optimize: 优化构建工具或运行时性能
* style:仅样式改动
* docs:仅文档新增/改动
* chore:构建过程或辅助工具的变动
*/
module.exports = {
  extends: [
    '@commitlint/config-conventional'
  ],
  rules: {
    'type-enum': [2, 'always', [
      'feature', 'update', 'fixbug', 'refactor', 'optimize', 'style', 'docs', 'chore'
    ]],
    'type-case': [0],
    'type-empty': [0],
    'scope-empty': [0],
    'scope-case': [0],
    'subject-full-stop': [0, 'never'],
    'subject-case': [0, 'never'],
    'header-max-length': [0, 'always', 72]
  }
};
// 这些配置是什么意思?请自行查阅commitlint文档

最后我们需要在package.json中配置上我们的husky的选项,代码片段如下:

"scripts": {
    // 忽略
    "build": "node build/build.js" 
},
"husky": {
    "hooks": {
      // 重点
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" 
    }
}

这段配置告诉了git hooks ,当我们在当前项目中执行 git commit -m '测试提交' 时将触发commit-msg事件钩子并通知husky,从而执行 commitlint -E HUSKY_GIT_PARAMS命令,也就是我们刚开始安装的./node_modules/.bin/commitlint,它将读取commitlint.config.js配置规则并对我们刚刚提交的测试提交这串文字进行校验,若校验不通过,则在终端输出错误,commit终止。

2.3、commitlint工作原理

简单阅读了一遍huskycommitlint的源码,大概的执行过程是这样的,如图所示:

前端codeLint-- 为项目集成ESLint、StyleLint、commitLint实战和原理_第1张图片

如果上面这张图看不太懂,这没关系,但你至少要看懂下面这张图:

前端codeLint-- 为项目集成ESLint、StyleLint、commitLint实战和原理_第2张图片

上面我们阐述了git hooks, huskycommitlint的工作流程, 理解husky的工作原理非常重要, 后面还会用到它,请大家务必理解。

三、集成ESLint

大家知道JavaScript语法存在一些设计缺陷,编码风格也可以各不相同,举一个最简单的例子,在定义一个string时小A同学喜欢用双引号,小B同学习惯用单引号,我们不讨论谁的风格更加合理,但我们至少应该统一它,这将减少我们代码的管理成本。

在我们的项目中集成eslint已经成为解决这个问题的成熟方案,可以说任何中大型项目都应该使用ESlint来约束我们的JavaScript代码,接下来看一下我们如何在webpack构建的vue项目中集成eslint

3.1、安装配置eslint-cli

首先在开发环境下安装eslint, 代码如下所示:

npm install --save-dev eslint

commitlint一样, 这会在./node_modules/.bin/目录下创建一个名为eslint.cmd的执行脚本(在windows系统下生成的是cmd脚本,在linux下就是sh脚本咯,这由nodejs自动帮你处理),eslint.cmd是eslint包提供的cli工具。

在项目根目录创建名为.eslintrc.js的文件,eslint.cmd执行时会默认读取该文件中的配置,初始配置如下:

module.exports = {
  root: true,
  env: {
    es6: true,
    node: true
  },
  plugin:[],
  extends: [],
  rules:[]
}  

完成上面配置,我们就可以使用eslint的cli功能对我们的js代码进行校验咯,在根目录终端输入下面命令,校验当前目录下所有js文件,并修其中复可自动修复的错误,代码如下:

./node_modules/.bin/eslint ./** --fix

如果你的npm版本在5.2版本以上,可以使用npx来执行./node_modules/.bin下面的脚本更,这样加方便,如下:

npx eslint ./** --fix

从下图可以看出,eslint已经生效:

image

3.2、为eslint扩展配置和规则

当然仅仅是这些还不够,我们需要个性化的集成一些其他辅助的包或者自己配置一套属于自己的eslint环境,让它更符合我们项目的需要。

npm上有不少社区提供的共享配置,我们可以选择一种适合我们的配置,直接集成过来,比如我们在Github中搜索“eslint-config-” 则会发现有很多这种开源的共享配置可选,如图:

image

大家可以根据项目的需要,选择适合的配置,此处我们采用eslint-config-standard这个共享配置,执行安装:

npm install --save-dev eslint-config-standard

修改配置文件如下:

module.exports = {
  root: true,
  env: {
    es6: true,
    node: true
  },
  extends: [
    'standard'
  ]
}  

让我们深入 eslint-config-standard包内部一探究竟,看它到底做了什么,下面为它内部的部分代码段:

image

通过上图,我们可以发现,eslint-config-standard 内部同时扩展了eslint-plugin-importeslint-plugin-nodeeslint-plugin-promise等插件,它们的作用分别是:

  • eslint-plugin-import 使eslint支持对import/export 的识别和校验
  • eslint-plugin-node 使eslin支持对nodejs原生模块的识别和校验
  • eslint-plugin-promise 使支持对promise最佳实践的校验

Note: 如果大家没有使用 eslint-config-standard, 但还想支持上面的这些功能,请自己安装集成, 此处就不再展示自定义集成的代码。

3.3、让eslint支持vue的识别和校验

如果你是vue项目,还需要安装下面这个包:

npm install --save-dev eslint-plugin-vue

官网对eslint-plugin-vue的介绍“ This plugin allows us to check the