代码检查是一种静态的分析,常用于寻找有问题的模式或者代码,并且不依赖于具体的编码风格。对大多数编程语言来说都会有代码检查,一般来说编译程序会内置检查工具。
开发中,代码的静态质量检查在项目质量保障方面很重要,所以越来越多的开发者在项目构建流程或者源码控制系统中添加静态检查的 hook
,今天介绍的是如何在项目中配置一套代码检测规范。
eslint
ESLint 是一个开源的 JavaScript 代码检查工具。
ESLint 的初衷是为了让程序员可以创建自己的检测规则。所有的规则都是自由配置,各自独立 且 可插拔的(即可开启可关闭),可将结果设置成警告或错误。
安装
npm install --save-dev eslint babel-eslint#或yarn add eslint babel-eslint --dev #添加到devDependencies依赖项类别中复制代码
官网:
配置方式
1.使用 JavaScript 注释把配置信息直接嵌入到一个代码源文件中
2.配置一个独立的 文件,或者直接在 文件里的
eslintConfig
字段指定配置,ESLint 会查找和自动读取它们,再者,你可以在运行时指定一个任意的配置文件。
eslint --init
命令可以创建一个配置,这样就可以继承推荐的规则。
如果同一目录下.eslintrc 和package.json 同时存在,.eslintrc 优先级高会被使用,package.json 文件将不会被使用。复制代码
配置规则
off
或 0 关闭 规则warn
或 1 开启规则,使用警告级别的错误error
或 2 开启规则,使用错误级别的错误
配置项
parserOptions:解析器选项
env:使用
env
关键字指定你想启用的环境,并设置它们为true
。如下示例启用了 browser 和 Node.js 的环境:
{ "env": { "browser": true, "node": true }}复制代码
globals:使用
globals
指出你要使用的全局变量。将变量设置为true
将允许变量被重写,或false
将不允许被重写。
{ "globals": { "var1": true, "var2": false }}复制代码
root:为了将 ESLint 限制到一个特定的项目,在你项目根目录下的
package.json
文件或者.eslintrc.*
文件里的eslintConfig
字段下设置"root": true
。ESLint 一旦发现配置文件中有"root": true
,它就会停止在父级目录中寻找。extends:
extends
属性值可以由以下组成:plugin:
包名 (省略了前缀,比如,
vue
)/
配置名称 (比如
recommended
)
extends: ['plugin:vue/recommended', 'eslint:recommended'],//表示采用vue和eslint推荐的核心规则复制代码
rules:启用的规则及其各自的错误级别.
所有的规则 默认都是禁用的。在配置文件中,使用"extends": "eslint:recommended"
来启用推荐的规则,报告一些常见的问题。
推荐规则如下:
禁用 console
禁用 debugger
强制所有控制语句使用一致的括号风格
要求使用 ===
和 !==
强制函数定义中最多允许的参数数量
强制把变量的使用限制在其定义的作用域范围内
强制使用骆驼拼写法命名约定
要求或禁止文件末尾存在空行
禁用未声明的变量,除非它们在 /*global */
注释中被提到
要求使用 let
或 const
而不是 var
max-depth 强制可嵌套的块的最大深度
强制一行的最大长度
max-nested-callbacks 强制回调函数最大嵌套深度
comma-spacing 强制在逗号前后使用一致的空格
强制在 function
的左括号之前使用一致的空格
强制在圆括号内使用一致的空格
和es6有关 的规则:
强制箭头函数的箭头前后使用一致的空格
强制在块之前使用一致的空格
要求或禁止使用分号代替 ASI
指定程序中允许的最大环路复杂度
禁止可以在有更简单的可替代的表达式时使用三元操作符
强制使用一致的反勾号、双引号或单引号
禁止出现未使用过的变量
强制函数中的变量要么一起声明要么分开声明
禁止修改const声明的变量
...
配置原则
能够帮之发现代码错误的规则,都需开启
配置不依赖于某个具体项目,应尽可能合理
帮助保持团队的代码风格统一,不限制开发体验
<!--关于更多eslint的规则和细节配置可参考官网~-->
.eslintignore
三方库忽略检测可在.eslintignore 中配置
third-party复制代码
关于git钩子
Git 能在特定的重要动作发生时触发自定义脚本。
钩子都被存储在 Git 目录下的 hooks 子目录中。 也即绝大部分项目中的 .git/hooks 。 当你用 git init 初始化一个新版本库时,Git 默认会在这个目录中放置一些示例脚本。 这些示例的名字都是以 .sample 结尾,如果你想启用它们,得先移除这个后缀。 把一个正确命名且可执行的文件放入 Git 目录下的 hooks 子目录中,即可激活该钩子脚本。
提交工作流钩子pre-commit
钩子在键入提交信息前运行。 它用于检查即将提交的快照,例如,检查是否有所遗漏,确保测试运行,以及核查代码。 如果该钩子以非零值退出,Git 将放弃此次提交,不过你可以用 git commit --no-verify
来绕过这个环节。 你可以利用该钩子,来检查代码风格是否一致(运行类似 lint
的程序)、尾随空白字符是否存在(自带的钩子就是这么做的),或新方法的文档是否适当。
如果把 Lint 挪到本地,并且每次提交只检查本次提交所修改的文件,上面的痛点就都解决了。Feedly 的工程师 开发的 就是基于这个想法,其中 staged 是 Git 里面的概念,指待提交区,使用 git commit -a
,或者先 git add
然后 git commit
的时候,你的修改代码都会经过待提交区。
git钩子创建
如果项目使用@vue/cli 脚手架生成的,官方文档提到 ,cli服务下有个Git Hook。
在安装之后,
@vue/cli-service
也会安装 ,它会让你在package.json
的gitHooks
字段中方便地指定 Git hook。{ "gitHooks": { "pre-commit": "lint-staged"}}复制代码
yorkie
fork 自 且并不和之后的版本兼容。
vue creat hello-world复制代码
之后查看hooks目录,已经有git钩子了。
在Package.json中添加如下
"gitHooks": { "pre-commit": "lint-staged" }, "lint-staged": { "*.{js,vue}": [ "vue-cli-service lint", "git add" ] }复制代码
如果你的项目不是 用脚手架 生成的,那就需要安装husky。
未安装husky前
执行npm install husky --save-dev复制代码
相应package.json配置如下
"husky": { "hooks": { "pre-commit": "lint-staged" } }, "lint-staged": { "*.{js,vue}": [ "eslint", "git add" ], },复制代码
你也可以通过 使用.huskyrc, .huskyrc.json or .huskyrc.js 这样的文件来配置hooks
补充说明
husky类似的工具在安装的时候会创建相关钩子npm在install和uninstall的时候可以执行脚本删除依赖不要在package.json中直接删除,而是用npm uninstall来删除复制代码
lint-staged : 前端文件过滤工具
Run linters on git staged files
如上package.json中提到lint-staged,对本次被commited中的所有.js
和 .vue
文件,执行eslint
命令和git add
命令
npm install -D lint-stagedyarn add --dev lint-staged复制代码
之后在项目中写了一个错误语法,验证 pre-commit,
接下来commit时可以看到控制台语法报错,lint生效了
这样我们就可以在提交代码之前 及时修正代码规范和错误。
附vue中的.eslintrc.js文件,仅供参考~
module.exports = { root: true, parserOptions: { parser: 'babel-eslint', sourceType: 'module' }, env: { browser: true, node: true, es6: true, }, extends: ['plugin:vue/recommended', 'eslint:recommended'], // add your custom rules here //it is base on https://github.com/vuejs/eslint-config-vue rules: { 'no-console': 1, 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, 'no-var': 2, 'no-undef': 1, 'camelcase': 0, 'eol-last': 0, 'block-scoped-var': 0, 'eqeqeq': 2, 'max-params': [1, 6], 'max-depth': [1, 6], 'max-nested-callbacks': [1, 3], 'comma-spacing': [2, { before: false, after: true }], 'arrow-spacing': 2, 'max-len': [2, 120, 4, { ignoreUrls: true, ignoreComments: true }], 'key-spacing': [2, { beforeColon: false, afterColon: true }], 'space-before-function-paren': [2, { anonymous: 'always', named: 'never' }], 'space-in-parens': [2, 'never'], 'space-before-blocks': 2, 'keyword-spacing': 2, 'semi': [2, 'always'], 'complexity': [2, 20], 'curly': [2, 'all'], 'no-unneeded-ternary': 2, 'quotes': [2, 'single'], 'no-unused-vars': [2, { 'vars': 'all', 'args': 'after-used', 'ignoreRestSiblings': false }], 'object-curly-spacing': [2, 'always', { objectsInObjects: false }], 'vue/attribute-hyphenation': [2, 'always'], 'vue/html-indent': [1, 4], 'vue/html-quotes': [2, 'double'], 'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }], 'vue/order-in-components': 2 }}复制代码
参考链接:
下面是本人的公众号,欢迎关注,不定期更新技术文章,一起成长,谢谢