Code Lint是前端工程化中的一个重要环节(what is code lint?),它能够帮助咱们在部署代码到生产环境以前及时发现错误并纠正它们,也能够规范咱们的编码习惯,让团队的代码风格保持统一。css
Code Lint的工做原理是借助一些lint工具对代码进行静态分析,并在合适的时机触发校验,提示错误。html
Note:本文可能没法覆盖全部知识点,如有知识盲区请主动查阅补齐,也能够在文章下方留言交流。前端
随着nodejs和前端工程化的发展,前端圈内产出了不少成熟的Lint工具,主要包括:vue
eslint
规范并校验 ECMAScript/JavaScript code的编写tslint
规范并校验 TypeScript code的编写stylelint
规范并校验css/scss/less code的编写commitlint
负责校验commit msg是否符合规范prettier
或 beautifyjs
统一代码排版格式除此以外,咱们还须要一些辅助的工具:node
husky
可以监听git hooks的nodejs包,让nodejs开发者处理git hooks任务变得更加容易lint-staged
能够将git“已暂存(staged)”的文件做为参数传入你要执行的shell script之中读到此处,你可能对这些工具的做用和用法仍然心存疑惑,不过不要紧,你们暂且只须要知道咱们将用这些工具对咱们的代码进行各环节的严格的校验便可,接下来让咱们深刻了解它们。react
相信你们对Git并不陌生,不知你们是否有过这种经历,本身提交git commit msg本身却看不懂。在小的团队里,可能咱们更注重的是业务产出,并不在意这些细节。随着团队的壮大,commit msg规范化相当重要,他意味着咱们是否清楚本身和同事对代码干了什么,在代码排错、回滚甚至是甩锅时起到了关键性做用。linux
本着“工具比人更可靠”的原则,咱们指望经过在项目中集成一些工具,从而实如今执行git commit -m 'msg'
时可以自动的对msg内容
进行校验,无需额外执行其余命令,husky
和 commitlint
刚好能解决咱们这个痛点。webpack
在正式集成commitlint
以前,先要介绍一下git hooks, 顾名思义hooks
为“钩子”之意,它是“发布订阅模式”的一种实现,和前端中的DOM事件(click、hover等)类似,Git也预先定义了一些“事件钩子”如“commit-msg”、“pre-commit”等,当咱们执行对应的Git操做时会触发它们,从而通知订阅该事件的shell script文件
处理咱们要进行的任务,这些shell脚本文件存放在项目根目录下的.git/hooks 目录中,如图所示:
git
咱们能够经过编写这些shell script文件
定制咱们的校验任务,但前端工程师大多对linux/windows shell并不擅长,这和咱们平时的工做重心有关, 所以咱们经过编写git hooks脚原本优化前端工做流的这条道路十分艰难。Nodejs改变了这一切,它让JavaScript拥有了控制“操做系统”的能力,你只须要安装nodejs包husky,它会帮咱们自动生成.git/hooks目录下的shell script
,咱们即可以很轻松的使用更熟悉的Nodejs处理git hooks
任务,而无需关注shell script的实现细节。es6
执行下面命令, 在开发环境中安装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 hooks
和husky
的理解。
固然不要忘记咱们今天的主角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终止。
简单阅读了一遍husky
和commitlint
的源码,大概的执行过程是这样的,如图所示:
若是上面这张图看不太懂,这不要紧,但你至少要看懂下面这张图:
上面咱们阐述了git hooks
, husky
和 commitlint
的工做流程, 理解husky
的工做原理很是重要, 后面还会用到它,请你们务必理解。
你们知道JavaScript语法存在一些设计缺陷,编码风格也能够各不相同,举一个最简单的例子,在定义一个string时小A同窗喜欢用双引号,小B同窗习惯用单引号,咱们不讨论谁的风格更加合理,但咱们至少应该统一它,这将减小咱们代码的管理成本。
在咱们的项目中集成eslint
已经成为解决这个问题的成熟方案,能够说任何中大型项目都应该使用ESlint来约束咱们的JavaScript代码,接下来看一下咱们如何在webpack构建的vue项目中集成eslint
。
首先在开发环境下安装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已经生效:
固然仅仅是这些还不够,咱们须要个性化的集成一些其余辅助的包或者本身配置一套属于本身的eslint环境,让它更符合咱们项目的须要。
npm上有很多社区提供的共享配置,咱们能够选择一种适合咱们的配置,直接集成过来,好比咱们在Github中搜索“eslint-config-” 则会发现有不少这种开源的共享配置可选,如图:
你们能够根据项目的须要,选择适合的配置,此处咱们采用eslint-config-standard
这个共享配置,执行安装:
npm install --save-dev eslint-config-standard
修改配置文件以下:
module.exports = { root: true, env: { es6: true, node: true }, extends: [ 'standard' ] }
让咱们深刻 eslint-config-standard
包内部一探究竟,看它到底作了什么,下面为它内部的部分代码段:
经过上图,咱们能够发现,eslint-config-standard
内部同时扩展了eslint-plugin-import
、eslint-plugin-node
和eslint-plugin-promise
等插件,它们的做用分别是:
Note: 若是你们没有使用 eslint-config-standard
, 但还想支持上面的这些功能,请本身安装集成, 此处就再也不展现自定义集成的代码。
若是你是vue项目,还须要安装下面这个包:
npm install --save-dev eslint-plugin-vue
官网对eslint-plugin-vue
的介绍“ This plugin allows us to check the <template> and <script> of .vue files with ESLint.”集成这个插件,将使eslint
拥有处理.vue文件
的能力。
此外咱们还须要安装 babel-eslint
包,安装命令以下:
npm install --save-dev babel-eslint
babel-eslint
是一款es语法解析器,使用它解析代码能够提供一些es实验阶段语法的校验支持, 最后咱们完整的eslint配置以下:
module.exports = { root: true, env: { es6: true, node: true }, parserOptions: { parser: 'babel-eslint' }, extends: [ 'plugin:vue/essential',// 识别vue语法,并提供vue默认校验规则 'standard' ], rules:[]// 你要覆盖的一些规则 }
若是你们还须要修改配置或者须要其余包的集成,请本身去完成扩展哦,这是对你们动手能力的小小考验。
stylelint和eslint有类似的做用和原理,只不过校验对象不一样,它主要用来校验你的样式代码,如css、scss、less等,这里就不作过多介绍,相信聪明的你能够从刚刚eslint的文章中作到触类旁通,直接上代码:
npm install --save-dev stylelint npm install --save-dev stylelint-config-standard
在本地建立名为.stylelintrc.js
的配置文件,配置以下:
"use strict"; module.exports = { ignoreFiles: [ "./**", "!./client/views/**/*.vue", "!./client/views/**/*.scss", "!./client/styles/**/*.scss", "!./client/plugin/**/*.vue", "!./client/plugin/**/*.scss" ], extends: ["stylelint-config-standard"], rules: { // 这里能够覆盖一些配置 } };
测试一下校验能力,项目根目录输入代码:
npx stylelint ./ --fix
上面代码会默认读取.stylelintrc.js
的配置,忽略你不须要校验的目录。
咱们知道eslint能够约束JavaScript的用法,可是它约束代码排版格式的能力却很是有限,同时它不能约束css、scss、html等,若想为咱们的代码格式化加上强约束,咱们还须要像相似prettier
或 beautify
这样的工具, 特别是prettier
它能够配合eslint使用。
prettier
对react
和jsx
支持的很好,但遗憾的是prettier
格式化vue
的能力并无那么强大,可配置项也是少的可怜,阿三没有采用,而且考虑到工具链的调整须要渐进完善,阿三我也不太想立刻就作格式化的强校验,感兴趣的同窗能够本身研究一下。
外部连接:prettier对vue的格式化能力有限
上面咱们讲了,如何为咱们的项目集成commitlint
、eslint
和stylelint
, 最终实现了,当咱们执行git commit -m '测试提交'
时,会对commit-msg的规范性进行校验校验,也能够在咱们的项目根目录执行npx eslint ./ --fix
或npx stylelint ./ --fix
来校验和修复咱们的代码。
但实际上除了commit-msg的校验, 已经知足了咱们真实的场景,后面的cli手动校验还不能知足咱们项目的需求,咱们指望的是自动化的完成这一切。
那什么时机进行自动lint更适合呢?这取决于你的需求,下面是我总结的一些常见的校验时机。
Soft lint是阿三我本身起的名字,也就是 “软校验”的意思,顾名思义它并非必须的,但它是很是必要的,它的使命是在开发环境下提醒开发者哪里出现了错误,请提早修正它们,是一种工具加持,有利于提高你排错的效率。
Soft lint通常是指在开发者的编辑器上完成的校验,属于“本地校验” ,同时它也是 “增量校验”,由于大多数状况下编辑器都只会校验你已经打开过的文件,固然也能够配置为“全量”的,可是这将会十分消耗电脑性能。
让咱们以vscode为例,看一下如何利用vscdoe的插件实现对项目代码的soft lint。
首先打开vscode的插件选项,搜索并安装ESLint
插件和stylelint
插件,安装完成后,重启你vscode, 打开你项目中的.vue或.js
文件,发现已经能够进行校验了,就这么简单,咱们不须要再进行多余的配置。
为何能够无需配置?咱们以vscode plugin Eslint
为例,打开该插件的官方介绍,能够看到这样一段话,“If you have installed ESLint locally then run .node_modules.bineslint --init under Windows and ./node_modules/.bin/eslint --init under Linux and Mac.”, 这看起来彷佛很熟悉,它正是执行了咱们上面经过npm安装的eslint
和stylelint
这两个包的cli脚本,你刚刚已经配置好了,所以能够安装即用,是否是很简单。
虽然说咱们已经在本地编辑器中安装了 vscode plugin Eslint
和 vscode plugin stylelint
,可是这仍然不太到位,它只是一种辅助加持,并不能作到真正的“硬限制”,咱们但愿经过一种方式,新人下载项目代码后便可自带校验功能(npm install一下开箱即用),无需再手动配置任何东西。咱们尝试和commitlint
同样在commit环节同时完成eslint
和stylelint
的校验,若校验不经过,则没法提交代码,阿三称之为“hard lint”。
咱们仍然指望它是一种“增量校验”,由于若是每次执行git commit -m
都要执行npx eslint ./** --fix
对项目中全部文件作一次校验,老板都要等破产了,实在是太慢了,咱们只需对Git中处于 staged
状态(git add的文件)的文件进行校验便可。
前面咱们讲过,想要在执行 git commit时进行一些自定义的操做, 咱们能够借助husky
监听git hooks
的能力,此时,咱们能够监听pre-commit
钩子,也就是说它会比commit-msg
钩子先触发,优先进行eslint
和stylelint
的校验,校验经过后再进行commitlint
的校验。
前面咱们之前安装了husky
, 那么咱们如何实现只对staged的文件进行“增量校验”呢?此时须要借助另一个包lint-staged
,执行下面命令:
npm install --save-dev lint-staged
而后在package.json文件中,增长下面配置(注意这里只是增长配置,别傻乎乎的把本身的原有配置给覆盖了):
{ "scripts": { "eslint:fix": "eslint --fix --ext \".js,.vue\"", "eslint:lint": "eslint --ext \".js,.vue\"", "stylelint:fix": "stylelint \"./**\" --fix" }, "husky": { "hooks": { "pre-commit": "lint-staged", "commit-msg": "commitlint -E HUSKY_GIT_PARAMS" } }, "lint-staged": { "linters": { "*.{scss,css}":[ "npm run stylelint:fix", "git add" ], "*.vue": [ "npm run stylelint:fix", "npm run eslint:fix", "git add" ], "*.{js}": [ "npm run eslint:fix", "git add" ] }, "ignore": [ "**/test/**" // 你要忽略的其余目录... ] } }
注意"lint-staged"这个配置,它会匹配Git中处于staged
状态的文件名,并针对这些匹配到的文件执行相对应的脚本,以vue文件为例,它会你在执行git commit -m 'test'
时,依次执行npm run stylelint:fix
、npm run eslint:fix
和 git add
,若是没有错误或者错误能被自动修复(--fix), 则会将改动自动add 将修复后的代码加入 git staged, 继续进行commitlint
的校验,若所有经过,才会生成一个新的commit,它的流程以下图:
除了上面讲的在编辑器中进行“soft lint” 和在commit阶段进行“hard lint”以外,咱们还能够在“webpack的loader阶段”或“CI持续集成远端”进行校验,但这不必定是必须的,须要看大家公司的是否须要这种校验,感兴趣的同窗能够本身研究一下。
若是你们在阅读过程当中遇到难以理解的问题,必定要尝试主动去寻找答案,培养本身独立解决问题的能力,欢迎留言评论。