Eslint-配置项

387 阅读5分钟

背景

工作中遇到了一个问题,即eslint-plugin-importimport/no-unresolved规则在识别路径别名时存在报错问题,当时使用了eslint-import-resolver-custom-alias进行解决,但是不知道原因,因此为了解决这个问题,因此从eslint配置项开始看

root

可选值为true

作用:停止向父元素目录查找规则

例如有如下目录结构:

template
  - package.json
  - .eslintrc.js
  - src
    - login
      - .eslintrc.js
      - login.tsx

一般情况下,对于 login.tsx 这个文件校验规则是 login 目录下的 .eslintrc.jstemplate 目录下 .eslintrc.js 之间共同作用的结果,如果两个配置文件的规则产生冲突,那么以最近的规则为准,即 login 目录下的 .eslintrc.js 文件

但是假如在 login 目录下的校验文件中设置 root: true,那么校验规则不再向上寻找,即 login.tsx 文件的校验规则受到当前 .eslintrc.js 校验文件的影响

globals

常用的配置项为 readonlytrue

当使用一个自定义全局变量时需要配置

例如:

console.log(abc);
{
    "globals": {
        abc: true,
        abc: 'readonly',
    }
}

env

指定运行环境,可以理解为提供了批量的 globals 的集合,可以查看globals这个包

{
  env: {
    browser: true, // 浏览器
    es2020: true // es支持版本
  },
}

例如,如果在 node 项目中需要用到全局变量 __dirname,那么 env 需要加一下 node: true,否则eslint校验时会出错

ignorePatterns

校验时忽略某些文件和目录,也可以采用.eslintignore来定义

{
  ignorePatterns: ['dist', '.eslintrc.cjs'],
}

parse

例如:

{
  parser: '@typescript-eslint/parser',
}

解析器,用于解析文件,这个也就是 eslint 识别文件的核心,默认使用 Espree 进行解析

举一个简单的例子

const ast = espree.parse('let foo = "bar"', { ecmaVersion: 6 });
console.log(ast);

得到如下结果:

// Node
{
  type: 'Program',
  start: 0,
  end: 15,
  body: [
    // Node
    {
      type: 'VariableDeclaration',
      start: 0,
      end: 15,
      // Node[]
      declarations: [
        {
          type: 'VariableDeclarator',
          start: 4,
          end: 15,
          id: {
            type: 'Identifier',
            start: 4,
            end: 7,
            name: 'foo'
          },
          init: {
            type: 'Literal'
            start: 10,
            end: 15,
            raw: '"bar"',
            value: 'bar'
          }
        }
      ],
      kind: 'let'
    }
  ],

  // 解析的类型 script module commonjs
  sourceType: 'script'
}

从上面的解析出的代码可以看到,其实就是把代码解析成抽象语法树,然后对抽象语法树进行校验

其他的解析器有:

目前已经不活跃了

早期的 Espree 就是基于 Esprima 一个分支扩展出来的

ESLint 的默认解析器和核心规则只支持最新的最终 ECMAScript 标准,不支持 Babel 提供的实验性(如新功能)和非标准(如 Flow 或 TypeScript 类型)语法。@babel/eslint-parser 是一个解析器,它允许 ESLint 在由 Babel 转换的源代码上运行。

例如proposal-partial-application这个语法:

const code = `
let a = 3;
const f = (x, y) => x + y;

const g = f(?, a);

g(1); // 4
`;

使用 Espree 并不能解析出以上的语法,但是使用 @babel/eslint-parser 可以,只需要在 babel 中安装 @babel/plugin-proposal-partial-application 这个插件,然后在 babel 配置文件中配置

module.exports = {
  presets: [
    ["@babel/preset-env"]
  ],
  plugins: ["@babel/plugin-proposal-partial-application"]
};

@babel/eslint-parser 的差异是虽然可以解析 TypeScript,但是并不支持在 TypeScript 进行校验

parseOptions

上面的虽然指定了解析器,但是还需要一些配置参数来控制输出,因此由 parseOptions 来控制

{
  parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }
}

一些基本的配置:

  • ecmaVersion: ECMAScript版本
  • sourceType: 模块化的方式
  • allowReserved:允许使用保留字作为标识符(当前没必要设置,因为这个和ecmaVersion3有关)
  • ecmaFeatures jsx: true globalReturn impliedStrict

可以根据需要,自定义解析器可以额外添加一些参数配置

  • project
{
  parserOptions: {
    project: 'tsconfig.json',
  }
}

rules

ESlint自带了大量的内置规则,可以通过rules来开启或者关闭

off或者0warn或者1error或者2warnerror的差异是触发时是否退出代码

{
    rules: {
        // 'no-undefined': ['error'],
        'no-undefined': 'error'
    }
},

除了第一个参数外,后面的参数根据需要配置不同的参数,例如:

{
    rules: {
        quotes: ['error', 'double'],
        'react-refresh/only-export-components': [
            'warn',
            { allowConstantExport: true },
        ],
    }
}

extends

为了方便,通过该参数可以配置一系列校验规则

  • eslint:recommended: eslint默认推荐的规则
{
  extends: [
    'eslint:recommended',
  ]
}

如果取消其中的一些配置,可以使用 rules 进行覆盖

当然还有一些其他的规则,例如typescript中有plugin:@typescript-eslint/recommended,react相关的有plugin:react-hooks/recommended

命名规则:

例如plugin:react-hooks/recommended,那么这个插件名称叫做eslint-plugin-react-hooks,前面可自动省略

主要根据plugin的命名规则来设置,可查看

当然也可以通过自定义文件来引入拓展,例如一些已经配置的规则或者需要忽略的规则

{
  extends: [
    './xxx',
  ]
}

plugins

{
    plugins: ['react-refresh'],
    rules: {
       'react-refresh/only-export-components': [
          'warn',
          { allowConstantExport: true },
        ],
    }
}

自定义插件,最好发布到npm中来引用,不建议自定义路径,可以pnpm install ./xxx

这里可以看这个包eslint-plugin-custom-plugins

// no-foo.js
module.exports = {
    rules: {
      'no-foo': {
        meta: {
          messages: {
            avoidName: "不允许使用变量 '{{ name }}'"
          }
        },
        create: (context) => {
          return {
            Identifier(node) {
              if (node.name === "foo") {
                context.report({
                  node,
                  messageId: "avoidName",
                  data: {
                    name: "foo",
                  }
                });
              }
            }
          };
        }
      }
    }
  };
const noFooRule = require('./no-foo.js');

const rules = {
  'no-foo': noFooRule,
};

exports.rules = rules;

如果用extends默认设置,使用以下内容

const noFooRule = require("./no-foo.js");

const configs = {
  recommended: {
    plugins: ['example'],
    rules: {
      'example/no-foo': 'error',
    }
  }
};
const rules = {
  'no-foo': noFooRule,
};

exports.configs = configs;
exports.rules = rules;

settings

用于配置一些全局的设置,这些设置可以在代码中的规则定义中引用

这个可以看eslint-plugin-react

{
  "settings": {
    "react": {
      "createClass": "createReactClass",
      "pragma": "React",
      "fragment": "Fragment",
      "version": "detect",
      "flowVersion": "0.53"
    },
  }
}

overrides

用于覆盖某些特定文件的规则,这个我暂时没有用到过,之后如果用到再详细展开