首先 有一个包叫做eslint, 你所有的一切lint校验都来自于这个包 - 官方文档
涉及到的前置知识点
如下图所示,此时左侧选中的部分(printTips),右侧实时高亮显示
ESLint的运行原理
##Eslint使用
配置文件
-
eslint配置文件 .eslintrc.js 举例说明:
-
env - 预先定义那些环境中需要用到的环境变量,可用参数 es6 / node / browser 等
browser -- 会添加所有浏览器的环境变量,比如window
node -- 会添加所有nodeJS运行时的环境变量,比如global process等
es6 -- 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置
ecmaVersion
解析器选项为 6)commonjs - CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码
官方文档参考
-
extends - 指定扩展的配置,配置支持递归扩展,支持规则的覆盖和聚合。
可选属性值:
-
指定配置的字符串 - (配置文件的路径、可共享配置的名称(airbnb)、
eslint:recommended
或eslint:all
) -
字符串数组 - 数组每一项的配置继承写在前边的配置 - 例如
extends: ['eslint:recommended`', 'eslint:all'], // eslint:all的配置继承eslint:recommended的配置
-
官方链接传送门
-
plugins - 这里配置我们需要的lint插件
-
parser - parser选项- 解析器,即告诉eslint你要使用哪个解析器进行解析代码,它支持的选项常用的以下几种:
Espree - 这个是eslint默认使用的解析器 - 但是一旦我们使用babel的话,我们需要用babel-eslint
-
babel-eslint - 这个依赖包允许你使用一些实验性的特性的时候,依然可以使用eslint的语法检查。 主要指es6, es7 等等的.
@typescript-eslint/parser - typescript语法的解析器,tslint已经弃用,官方不再维护,不必关注。这个主要会支持一些typescript的语法,比如类型断言 const a! : number 或者在使用的时候会有 a as number 这种情况。
-
parserOptions - 在parser配置为babel-eslint的时候,必须配置这个选项,可选值 (。
ecmaVersion - 默认5, 可指定3、5、6、7、8、9、10,用来指定使用哪一个ECMAScript版本的语法。也可以设置基于年份的JS标准,比如2015(ECMA 6)
sourceType - 如果你的代码是ECMAScript 模块写的,该字段配置为
module
,否则为script
(默认值)ecmaFeatures - 该对象指示你想使用的额外的语言特性
)
- rules - 自定义规则配置 --优先级最高,可以覆盖掉我们在extends中配置启用的规则
- settings - 该字段定义的数据可以在所有的插件中共享。这样每条规则执行的时候都可以访问这里面定义的数据
module.exports = {
env: 'es6',
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module'
},
extends: ['eslint:recommended`', 'eslint:all'], // eslint:all的配置继承eslint:recommended的配置
rules: {
'no-unused-vars': [
'error',
// we are only using this rule to check for unused arguments since TS
// catches unused variables but not args.
{ varsIgnorePattern: '.*', args: 'after-used', argsIgnorePattern: '^_' }
],
// most of the codebase are expected to be env agnostic
'no-restricted-globals': ['error', ...DOMGlobals, ...NodeGlobals],
// since we target ES2015 for baseline support, we need to forbid object
// rest spread usage (both assign and destructure)
'no-restricted-syntax': [
'error',
'ObjectExpression > SpreadElement',
'ObjectPattern > RestElement'
]
},
settings: {
'import/resolver': { // This config is used by eslint-import-resolver-webpack
webpack: {
config: './webpack/webpack-common-config.js'
}
},
},
overrides: [
// tests, no restrictions (runs in Node / jest with jsdom)
{
files: ['**/__tests__/**', 'test-dts/**'],
rules: {
'no-restricted-globals': 'off',
'no-restricted-syntax': 'off'
}
},
// shared, may be used in any env
{
files: ['packages/shared/**'],
rules: {
'no-restricted-globals': 'off'
}
},
// Packages targeting DOM
{
files: ['packages/{vue,runtime-dom}/**'],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals]
}
},
// Packages targeting Node
{
files: ['packages/{compiler-sfc,compiler-ssr,server-renderer}/**'],
rules: {
'no-restricted-globals': ['error', ...DOMGlobals],
'no-restricted-syntax': 'off'
}
},
// Private package, browser only + no syntax restrictions
{
files: ['packages/template-explorer/**'],
rules: {
'no-restricted-globals': ['error', ...NodeGlobals],
'no-restricted-syntax': 'off'
}
}
]
}
个人常用配置项扩展说明:
eslint 配置文件常用的配置选项注意:
-
parser- 首先需要配置解析器,这个在目前的前端环境下是必须的,如果不配置就是采用默认的javascript解析器 - espree,我们一般使用babel-eslint。 有时候解析选项也是需要进行配置的parserOptions
-
env - 指定脚本运行的运行时环境,可以同时指定多个,具体见官方文档
-
extends - 指定我们启用哪一套eslint规则,一般启用标准规则, 这里可以写多个规则启用项目,后边的覆盖前边的,也可引入我们的自定义规则(既如此,我们就可以把我们习惯的规则引入,或者把我们自定义的插件配置在此处)
-
plugins - 这个地方配置第三方的插件,插件需要安装对应的npm包, 可以写多个,形式为字符串数组, 前缀eslint-plugin-可省略
-
rules - 此处启用的规则优先级最高,可以配置eslint的自有规则,也可配置从第三方插件中引入的规则(此处需要保证第三方插件的npm包已经安装).
-
overrides & files - 针对项目中特定的部分文件禁用eslint规则,可进行如下配置:
overrides: [ // tests, no restrictions (runs in Node / jest with jsdom) { files: ['**/__tests__/**', 'test-dts/**'], rules: { 'no-restricted-globals': 'off', 'no-restricted-syntax': 'off' } }, // shared, may be used in any env { files: ['packages/shared/**'], rules: { 'no-restricted-globals': 'off' } }, // Packages targeting DOM { files: ['packages/{vue,runtime-dom}/**'], rules: { 'no-restricted-globals': ['error', ...NodeGlobals] } }, // Packages targeting Node { files: ['packages/{compiler-sfc,compiler-ssr,server-renderer}/**'], rules: { 'no-restricted-globals': ['error', ...DOMGlobals], 'no-restricted-syntax': 'off' } }, // Private package, browser only + no syntax restrictions { files: ['packages/template-explorer/**'], rules: { 'no-restricted-globals': ['error', ...NodeGlobals], 'no-restricted-syntax': 'off' } } ]
编写一个Eslint插件
既然要写一个插件,必要明确插件要实现的功能目标,eslint插件可实现一个校验的规则。
#### 插件要实现的目标
- 禁止setTimout的第二个参数是数字。
- 进阶 - 规则增强 - 项目中禁止出现魔幻变量。
开发准备工作
-
eslint官方为了方便开发者开发插件,提供了Yeoman模版(generator-eslint), 它是一个脚手架工具,用于生成包含指定框架结构的工程化目录结构。
npm install -g yo generator-eslint
-
创建一个文件夹,用来存放你的项目
mkdir -p eslint-plugin-demo && cd eslint-plugin-demo
-
初始化eslint插件的目录结构
yo eslint:plugin
初始化eslint规则的模版文件
yo eslint:rule
生成之后的文件目录结构
├── README.md ├── docs // 使用文档 │ └── rules // 所有规则的文档 │ └── settimeout-no-number.md // 具体规则文档 ├── lib // eslint 规则开发 │ ├── index.js 引入+导出rules文件夹的规则 │ └── rules // 此目录下可以构建多个规则 │ └── settimeout-no-number.js // 规则细节 ├── package.json └── tests // 单元测试 └── lib └── rules └── settimeout-no-number.js // 测试该规则的文件
安装依赖
npm install
开始开发
有2个文件需要我们关注:
第一个 lib/rules/settimeout-no-number.js, 这个是规则模板文件,也是我们开发自定义规则的文件: (初始大致这个样子)
module.exports = {
meta: {
docs: {
description: "setTimeout 第二个参数禁止是数字",
},
fixable: null, // 修复函数
},
// rule 核心
create: function(context) {
// 公共变量和函数应该在此定义
return {
// 返回事件钩子
};
}
};
完整代码:
/**
* @fileoverview The second parameter of setTimeout is forbidden to be a number
* @author Arche
*/
"use strict";
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: "The second parameter of setTimeout is forbidden to be a number",
category: "Fill me in",
recommended: false
},
fixable: 'code', // or "code" or "whitespace" // 是否开启文件修复函数
schema: [
// fill in your schema
]
},
create: function(context) {
// variables should be defined here
//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------
// any helper functions should go here or else delete this section
//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------
return {
'CallExpression': (node) => {
if (node.callee.name !== 'setTimeout') return //检测是否是定时器,不是return
const parameterTime = node?.arguments[1]; // 获取第二个参数
if (!parameterTime) return // 如果第二个参数不存在则return
if(parameterTime.type === 'Literal' && typeof parameterTime.value === 'number') {
context.report({
node,
message: 'The second parameter is forbidden to be a number', // 这个提示信息需要和测试用例中的保持完全一致
fix: (fixer) => { // 这个是文件修复函数
const numberValue = parameterTime.value;
const statementString = `const countNumber = ${numberValue}\n`; // 修复语句
return [
fixer.replaceTextRange(node.arguments[1], numberValue), // 替换第二个参数位置
fixer.insertTextBeforeRange(node.range, statementString) // 在定时器前增加一条语句
]
}
})
}
}
};
}
};
第二个 tests/lib/rules/settimeout-no-number.js 这个是测试用例文件。
/**
* @fileoverview The seconed parameter of setTimeout is forbidden to be a
* @author Arche
*/
"use strict";
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
var rule = require("../../../lib/rules/setTimeout-no-number"),
RuleTester = require("eslint").RuleTester;
//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------
var ruleTester = new RuleTester({
parserOptions: {
ecmaVersion: 7, // 默认支持语法为es5
},
});
ruleTester.run("setTimeout-no-number", rule, {
valid: [
{
code: "let num = 1000; setTimeout(() => { console.log(1) }, num)"
},
{
code: 'setTimeout(()=>{ console.log(11) },someNumber)'
}
],
invalid: [
{
code: "setTimeout(() => {}, 1000)",
errors: [{
message: "The second parameter is forbidden to be a number",
type: "CallExpression"
}]
}
]
});
参考资料:
手摸手教你写个eslint插件以及了解eslint的运行原理
最全的Eslint配置模板,从此统一团队的编程习惯
官方文档
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!