作为一个前端开发,要保证团队的代码质量和代码风格保持一致,就需要使用 eslint 来进行代码检查,一个好的 eslint 配置可以让团队提高开发的幸福感。市面上已经有很多大公司团队定制了自己的 eslint 规则,例如:国外有 airbnb 的*eslint-config-airbnb,谷歌的eslint-config-google,国内的有阿里的eslint-config-ali*等等。

当然并非大厂的规则就一定适用于我们日常工作,所以有时候拿来即用也不是很方便,我们需要根据自己的项目需求来定制一套适合自己的 eslint 规则。

插件概念

要开发一个 eslint 插件,需要先了解以下几个概念:

AST

抽象语法树,一种用于表示代码结构的树形数据结构。eslint 默认使用 espree 作为其解析器,将源代码转换为 AST(抽象语法树)。espree 适用于 ES5、ES6 和 ES7 的 JavaScript 解析器,当然我们也可以配置其他解析器,例如@babel/eslint-parser,@typescript-eslint/parser 等等。

Context

eslint 执行过程的上下文环境变量,可以在当前执行检测的时候获取规则配置,访问源码,报告错误,修复语法等功能。

Rule

eslint 规则是一个函数,接受一个 context 对象,返回一个 visitor 对象,可以通过 visitor 获取解析的节点信息并进行相应的处理。

eslint 插件脚手架

可以通过 yo 命令来安装脚手架,yo 是 yeoman 的命令行工具,yeoman 是一个脚手架工具,可以通过它来快速搭建项目的基础结构。如果没有安装 yo,可以通过npm install -g yo来安装。

接下来安装 eslint 插件脚手架

npm install -g generator-eslint

安装完成后,我们创建一个文件夹,命名最好以eslint-plugin-xxx开头,然后到文件夹下运行yo eslint:plugin,会帮我们创建一个简单的 eslint 项目文件。

自定义规则实现

我们在刚创建的eslint-plugin-xxx文件夹根目录下运行yo eslint:rule,我们来简单实现一个功能,限制不在项目里面写console.log(xx)等代码

我们在lib/rules/no-console-log.js文件编写代码如下:

module.exports = {
meta: {
type: 'problem', // `problem`, `suggestion`, or `layout`
messages: {
noConsoleLog: 'no console log',
},
docs: {
description: 'no console log',
recommended: false,
url: null,
},
fixable: null, // Or `code` or `whitespace`
schema: [], // Add a schema if the rule has options
},
create(context) {
// 返回访问者对象
return {
// 当访问到CallExpression节点时触发
CallExpression(node) {
// 如果调用表达式的callee是console.log
if (
node.callee.type === 'MemberExpression' &&
node.callee.object.name === 'console' &&
node.callee.property.name === 'log'
) {
// 报告错误
context.report({
node,
messageId: 'noConsoleLog',
});
}
},
};
},
};

tests/lib/rules/no-console-log.js文件的内容如下:

/**
* @fileoverview no console log
* @author kelen
*/
'use strict';
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const rule = require('../../../lib/rules/no-console-log'),
RuleTester = require('eslint').RuleTester;
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
const ruleTester = new RuleTester();
ruleTester.run('no-console-log', rule, {
// 有效的测试用例
valid: [
// 不包含console.log的代码
"console.error('error');",
"console.warn('warn');",
"console.info('info');",
"console.debug('debug');",
"console.trace('trace');",
"console.dir('dir');",
"console.dirxml('dirxml');",
"console.table('table');",
"console.time('time');",
"console.timeLog('timeLog');",
"console.timeEnd('timeEnd');",
"console.group('group');",
"console.groupCollapsed('groupCollapsed');",
"console.groupEnd('groupEnd');",
"console.clear('clear');",
"console.count('count');",
"console.countReset('countReset');",
"console.assert('assert');",
],
// 无效的测试用例
invalid: [
// 包含console.log的代码,应该报告错误
{
code: "console.log('log');",
errors: [{ messageId: 'noConsoleLog' }],
},
],
});

接下来,执行npm run test,可以看到输出结果如下

最后我们可以把 eslint 发布到 npm 仓库里,然后就可以在其他项目里面使用了。

项目引入

在需要引入自定义插件的项目里安装该插件,npm i eslint-plugin-kelen -D,然后在.eslintrc.js文件配置如下。

module.exports = {
root: true,
plugins: ['kelen'],
rules: {
'kelen/no-console-log': 'error',
},
};

在项目输入console.log(12313);可以看到规则生效了。