ESLint介绍

1,259 阅读13分钟

前言

年前为公司升级了新的monorepo项目架构,近来不用加班,在家得闲。便想再搭个monorepo项目,随便记录一下。
用到以下pnpm + vite3 + vue3 + ESLint + Stylelint + TypeScriptmonorepe实战记录,此篇为其中一个的简单介绍。

了解ESLint

ESLint是代码检查工具,用于检查代码是否符合规范,通过一些规则来检查语法和约束代码风格。
使用ESLint有诸多好处

  1. 统一语法,比如约定不能使用var。
  2. 统一代码风格,比如约定结尾是否加分号,当团队多人协作时统一的编码风格至关重要。
  3. 避免一些低级错误,比如写错变量。
  4. 等等...

ESLint有两种工具

  • 一种是代码编辑(比如VS Code)的扩展工具,用于在编写代码时给予提示
  • 一种是npm包,通过node执行包相关命令检查代码。

ESLint使用

这里在一个vite + vue3的基础模板中加入eslint,其他项目的eslint配置都是相似的。

安装ESLint (npm包)

pnpm add eslint -D

配置ESLint

需要告知eslint需要用哪些规则,就得添加个配置文件。可以直接在package.json中配置,也可以在项目根目录下创建.eslintrc.*文件。
支持的格式按优先级顺序如下

  1. .eslintrc.js(优先推荐)
  2. .eslintrc.yaml
  3. .eslintrc.yml
  4. .eslintrc.json
  5. .eslintrc (官网提示弃用,但试了还能用。不过还是尽量用其他格式吧)
  6. package.json

还允许在文件下夹创建配置文件,比如在src下创建配置文件,此时src文件夹下文件的配置选项为:从src文件夹往父目录查找配置文件(直到遇到有root:true选项的配置文件,或到根目录),配置选项就是这些配置的组合,并且内层的选项优先级高。

在项目根目录下创建.eslintrc.cjs

// .eslintrc.cjs
module.exports = {}

打算一步步添加配置来简单介绍eslint的使用,所以没有使用命令快捷生成配置文件。
后面会介绍通过pnpx eslint --init来快速生成相应的配置文件。

常用命令

  • 执行校验 [pnpx] eslint [文件|文件夹|.]
// 校验main.js文件
pnpx eslint main.js

// 校验src文件夹下所有js文件
pnpx eslint src
  • 修复基础问题`--fix
// 添加--fix会自动修复一些不影响逻辑的基础问题
pnpx eslint src --fix
  • 指定校验的文件类型 --ext
// eslint默认只校验.js文件,可以通过--ext指定更多类型文件,逗号隔开
pnpx eslint src --ext .js,.vue

一般都会将命令写入package.json中

// package.json
{
  // ...
  "scripts": {
     // ...
    "lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
  }
}

一般常用的就这几个命令,了解更多命令请查看官网-命令行

配置选项介绍

前面只创建了个空的配置对象,还需要配置相应的选项,先了解它们。
项目当前只有一个js文件(src/main.js),先根据这个文件(作为最初案例代码)简单配置下选项以实现对它的校验。
image.png

parserOptions

指定想要支持的 JavaScript 语言选项

module.exports = {
  parserOptions: {
    // 支持的ECMAScript语法,默认ECMAScript 5。配置来支持其他语法
    ecmaVersion: 12,
    
    // 代码模块,选项包含:script(默认)、module
    sourceType: 'module',
    
    // 额外的语言特性
    //ecmaFeatures: {
      // 是否 允许在全局作用域下使用 `return` 语句
      //globalReturn: false, 
      
      // 是否 启用全局严格模板[strict mode] (如果 `ecmaVersion` 是 5 或更高)
      //impliedStrict: false,
      
      // 是否 支持jsx
      //jsx: false, 
      
      // 是否 启用实验性的 object rest/spread properties
      //experimentalObjectRestSpread: false,
    //}
  }
}

parser

配置eslint的解析器(解析代码并返回ast语法树),默认Espree,也可配置其他符合要求的解析器(比如esprima)

module.exports = {
  parser: 'esprima'
}

有些特殊文件还需要使用特征插件来解析,比如.vue文件需要使用vue-eslint-parser解析器进行解析,也可以在parser中配置

module.exports = {
  parser: 'vue-eslint-parser'
}

当还需要额外定义解析器时,可以在parserOptions.parser中配置。
比如已经配置了vuevue-eslint-parser解析器,还需要使用TypeScript@typescript-eslint/parser,就可以像下面这样配置。

module.exports = {
  parser: 'vue-eslint-parser',
  parserOptions: {
    parser: '@typescript-eslint/parser'
  }
}

解析器需要符合以下要求

  1. 它必须是一个 Node 模块,可以从它出现的配置文件中加载。通常,这意味着应该使用 npm 单独安装解析器包。
  2. 它必须符合 parser interface

rules

ESLint附带大量的规则,想要使用对应的规则,就需要将将规则ID配置以下值。

  • "off" 或 0 - 关闭规则
  • "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
  • "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)

有两种方式配置规则。以配置规则IDsemi(结尾是否有分号)为例

  1. 在配置文件中配置

    module.exports = {
      // ... 一些其他配置,没有配置其他rule
      rules: {
        semi: 2
      }
    }
    

    对案例代码
    image.png
    执行检测pnpx eslint src/main.js
    image.png
    如图:报了4个丢失分号错误。

  2. 也在项目文件中以注释的形式【不推荐在代码里嵌入eslint规则
    image.png
    再执行检测pnpx eslint src/main.js
    image.png
    如图,没报eslint的semi错误了

extends

一个配置文件可以被基础配置中的已启用的规则继承
大白话eslint配置文件可以继承其他配置文件的配置选项
当需要配置某些规范(比如内置规范、第三方规范...),则需要在extends选项中配置。

例如,假设有某个第三方配置包eslint-config-aaa
a,我们的配置文件.eslintrc.cjs内容如下

module.exports = { 
  // ...
  rules: { 
    semi: 2 
  },
  extends: 'eslint-config-aaa'
}

b,第三方配置包eslint-config-aaa的规则如下

module.exports = { 
  rules: { 
    indent: [2, 2],
    semi: 0
  }
}

c,那么继承最终规则如下

module.exports = { 
  rules: {
    indent: [2, 2],
    semi: 2
  }
}

eslint-config-aaa包的rules的属性indent被继承,而semi被覆盖,可通过rules覆盖extends中继承的规则。具体规则如下

rules 属性可以做下面的任何事情以扩展(或覆盖)规则:

  • 启用额外的规则
  • 改变继承的规则级别而不改变它的选项:
    • 基础配置:"eqeqeq": ["error", "allow-null"]
    • 派生的配置:"eqeqeq": "warn"
    • 最后生成的配置:"eqeqeq": ["warn", "allow-null"]
  • 覆盖基础配置中的规则的选项
    • 基础配置:"quotes": ["error", "single", "avoid-escape"]
    • 派生的配置:"quotes": ["error", "single"]
    • 最后生成的配置:"quotes": ["error", "single"]

extends可配置 指定配置的字符串(可用数组配置多个,比如extends: ['配置包1','配置包2']),并且会递归读取extends配置中的配置。 extends值可以是以下这些

  • 配置文件路径,例如

    module.exports = {
      // ...
      extends: './eslint.js' // ./eslint.js 是本地的一个其他eslint配置文件的路径
    }
    
  • 可共享配置名称可共享配置是个npm包,它输出一个配置对象。
    这个可共享配置的npm包要求前缀: eslint-config-。如比较流行的eslint-config-standard;还支持npmscoped modules,比如@scope/eslint-config-myconfig
    当配置时eslint-config-前缀可以省略,比如

    module.exports = {
      // ...
      // eslint-config-standard 的缩写
      extends: 'standard' 
    }
    
  • 插件(后面介绍)输出的规则,配置时需要以plugin:开头,比如

    module.exports = {
      // ...
      // eslint-plugin-vue 插件的缩写
      // plugin: ['vue'], 
      // 使用eslint-plugin-vue插件输入的vue3-recommended规则
      extends: 'plugin:vue/vue3-recommended' //
    }
    
  • eslint内置规则包

    • eslint:all 当前安装ESLint中 所有的规则不推荐使用
    • eslint:recommended 当前安装ESLint中 一些常用的规则,在规则页面 中被标记为 √ 的规则。
    module.exports = {
      // ...
      // 使用eslint推荐规则 eslint:recommended
      extends: 'eslint:recommended' 
    }
    

plugins

当ESLint提供的规则如果不能满足需求,就需要通过配置插件来为ESLint扩展规则。
比如想对vue文件进行校验,就可以通过plugins选项配置(配置选项时eslint-plugin-前缀可省略)。

下面以让eslint支持vue项目校验为例,演示如何使用插件和配置插件以及规则。

  1. 先安装以下依赖包:
    • vue-eslint-parser 解析vue文件的解析器
    • eslint-plugin-vue 为vue文件添加新规则的插件
    pnpm add vue-eslint-parser eslint-plugin-vue -D
    
  2. 修改eslint配置文件
    module.exports = {
      // ...
      parser: 'vue-eslint-parser',
      plugins: [
        // eslint-plugin-vue的缩写,eslint-plugin-可省略
        'vue'
      ],
      extends: [
         // 使用eslint-plugin-vue插件提供的vue3-recommended规则
        'plugin:vue/vue3-recommended'
      ]
    }
    
  3. 执行校验指令npx eslint src --ext .js,.vue image.png 可以看到已支持对vue文件校验了。

env

若想使用环境变量,比如浏览器下的window变量,需要开启对应的环境选项env。比如

module.exports = {
  env: {
    browser: true
  }
}

比较常用到的环境包括:

  • browser - 浏览器环境中的全局变量。
  • node - Node.js 全局变量和 Node.js 作用域。
  • commonjs - CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/WebPack 打包的只在浏览器中运行的代码)。
  • shared-node-browser - Node.js 和 Browser 通用全局变量。
  • es6 - 启用除了 modules 以外的所有 ECMAScript 6 特性(该选项会自动设置 ecmaVersion 解析器选项为 6)。
  • worker - Web Workers 全局变量。
  • amd - 将 require() 和 define() 定义为像 amd 一样的全局变量。
  • 更多可用环境

globals

当使用当前文件源文件未定义的变量时,no-undef规则将发出警告。此时就可以通过globals选项来定义全局变量以规避no-undef警告。

module.exports = { 
  globals: { 
    var1: 'writable', // writable 可写
    var2: 'readonly', // readonly 仅读
    var3: 'off' // off 禁用该全局变量
  }
}

注意: 要启用no-global-assign规则来禁止对只读的全局变量进行修改。

overrides

当需要对某些文件规则重写时,可以使用overrides选项。
例如 bin和lib下的js文件的规则重写。

module.exports = {
  overrides: [{
    files: ['bin/*.js', 'lib/*.js'],
    excludedFiles: '*.test.js',
    rules: {
        quotes: ['error','single']
    }
  }]
}

.eslintignore

当需要告诉ESLint忽略某些文件时,可以在项目根目录创建.eslintignore文件

# 这行是注释
node_modules
dist

也可以直接在package.json中配置

{

  "eslintIgnore": ["node_modules","dist"]
}

命令形式创建配置文件。

就是直接执行npx eslint --init命令,然后根据项目情况选择就行,推荐直接跳到下一节点。下面记录的有点不太必要,但当时记都记录了就没删掉-

D:\data\st\vue\vite-vue3>npx eslint --init
You can also run this command directly using 'npm init @eslint/config'.        
Need to install the following packages:
  @eslint/create-config@0.4.2
Ok to proceed? (y)

提示需要安装对应的包@eslint/create-config,直接按回车

? How would you like to use ESLint? ...
  To check syntax only 
  To check syntax and find problems
> To check syntax, find problems, and enforce code style

询问如何使用ESLint?根据实际需要自行选择,
这里选择第三种 检查语法、发现问题并强制执行代码样式

? What type of modules does your project use? ... 
> JavaScript modules (import/export)
  CommonJS (require/exports)
  None of these

项目用哪种模块?项目用的ESM,所以也选这个

? Which framework does your project use? ... 
  React
> Vue.js
  None of these

用的哪种框架?项目用的Vue

? Does your project use TypeScript? » No / Yes

是否使用TypeScript?因当时用vite建demo没选ts模板,所以这里也选No

? Where does your code run? ...  (Press <space> to select, <a> to toggle all, <i> to invert selection)
√ Browser
√ Node

代码在哪运行,会对应开启配置env选项的环境变量。都勾选

? How would you like to define a style for your project? ... 
> Use a popular style guide
  Answer questions about your style

定义哪种风格配置,这里选第一种用流行的风格配置规则

? Which style guide do you want to follow? ...
  Airbnb: https://github.com/airbnb/javascript
> Standard: https://github.com/standard/standard        
  Google: https://github.com/google/eslint-config-google
  XO: https://github.com/xojs/eslint-config-xo

遵循哪种风格?前两种用的多点,有些规则不太同,Airbnb要求必须加行尾分号、函数名后面必须加空格,Standard则反之。这里对比我更喜欢第二种 Standard,不过团队开发规则都是用定制的多,比如我们开发就是用的公司团队定制的规则。

? What format do you want your config file to be in? ... 
> JavaScript
  YAML
  JSON

配置文件使用哪种风格,都可,这里推荐使用JavaScript。

Checking peerDependencies of eslint-config-standard-with-typescript@latest
The config that you've selected requires the following dependencies:

eslint-plugin-vue@latest eslint-config-standard-with-typescript@latest @typescript-eslint/eslint-plugin@^5.43.0 eslint@^8.0.1 eslint-plugin-import@^2.25.2 eslint-plugin-n@^15.0.0 eslint-plugin-promise@^6.0.0 typescript@*
? Would you like to install them now? » No / Yes

提示需要安装这种依赖,是否现在安装,Yes、

? Which package manager do you want to use? ... 
  npm
  yarn
> pnpm

用哪种包管理工具,看各自情况,我选用pnpm

最后这里根据选择自动生成.eslintrc.mjs文件,默认内容如下(默认内容一般还需要修改配置以适应团队规范)。

module.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true
  },
  
  extends: [
    'plugin:vue/vue3-essential',
    'standard'
  ],
  overrides: [
  ],
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  plugins: [
    'vue'
  ],
  rules: {
  }
}

VS Code安装eslint插件

通过eslint npm包可以通过命令行来检查代码,还可以通过VS Code的eslint插件使我们在写代码的时候就能给出提示。
在商店安装ESLint插件
image.png
不需要额外配置,eslint插件会根据前面配置的eslint配置文件对代码进行提示。 image.png

结合prettier

eslint专注于检查代码规范,也可以格式化代码,主要保证代码质量。
prettier专注于格式化代码,不会修改代码内容,保证代码美观,而且prettier还支持格式化其它语言的代码。
eslint虽然也能格式化代码,但有一些格式问题还是需要通过prettier。
ESLint与Prettier容易有一些规则冲突,可通过eslint-config-prettiereslint-plugin-prettier,使配置以prettier为重。如下步骤配置,

1,使用前需先安装依赖

pnpm add eslint-config-prettier eslint-plugin-prettier prettier -D

2,修改.eslintrc.cjs

module.exports = {
  extends: [
    // ...
    // eslint-plugin-prettier插件输入的内置规则,配置在最后
    'plugin:prettier/recommended'
  ]
}

3,新增.prettierrc.cjs可以新增规则,新增.prettierignore配置忽略文件(和.eslintignore配置类似)。

// .prettierrc.cjs 常规配置
module.exports = {
    // 一行最多 100 字符
    printWidth: 100,
    // 使用缩进符,false表示使用空格缩进
    useTabs: true,
    // 使用多少个空格缩进,个人习惯2个,也很多人喜欢是用4个缩进
    tabWidth: 2,
    tabSize: 2,
    // 行尾需要有分号
    semi: false,
    // 使用单引号
    singleQuote: true,
    // 对象的 key 仅在必要时用引号
    quoteProps: 'as-needed',
    // jsx 不使用单引号,而使用双引号
    jsxSingleQuote: false,
    // 末尾不需要逗号 'es5'  none
    trailingComma: 'es5',
    // 大括号内的首尾需要空格
    bracketSpacing: true,
    // jsx 标签的反尖括号需要换行
    jsxBracketSameLine: false,
    // 箭头函数,只有一个参数的时候,也需要括号
    arrowParens: 'always',
    // 每个文件格式化的范围是文件的全部内容
    rangeStart: 0,
    rangeEnd: Infinity,
    // 不需要写文件开头的 @prettier
    requirePragma: false,
    // 不需要自动在文件开头插入 @prettier
    insertPragma: false,
    // 使用默认的折行标准
    proseWrap: 'preserve',
    // 根据显示样式决定 html 要不要折行
    htmlWhitespaceSensitivity: 'css',
    // 换行符使用 lf 结尾是 \n \r \n\r auto
    endOfLine: 'lf',
}; 

eslint-plugin-prettier: prettier插件,将prettier规则作为eslint规则运行。该插件还内置了一个规则配置recommended
eslint-config-prettier: prettier配置,该配置关闭了一些与prettier冲突的eslint规则。
上面第2步配置了eslint-plugin-prettier插件的内置推荐配置recommended,该配置内容如下。

{
   // 开启了 eslint-config-prettier 配置
   // 它关闭了一些与Prettier冲突的ESLint规则。
  "extends": ["prettier"],
  // 注册了该插件
  "plugins": ["prettier"],
  "rules": {
     // 启动该插件提供的规则,以ESLint运行该规则
    "prettier/prettier": "error",
    "arrow-body-style": "off",
    "prefer-arrow-callback": "off"
  }
}

通过以上配置可解决一些冲突,但还是有可能出现冲突。比如.eslintrc.* rules中和.prettierrc.* 中有配置相反的规则就会有冲突。
假设perttier配置结尾需要分号,eslint配置结尾不能有分号。 image.png
image.png

通过eslint-config-prettiereslint-plugin-prettier可解决prettier和eslint冲突问题,若还有冲突检查pretter(.prettierrc.* )和eslint(.eslintrc.* )的配置是否一致。

结尾

eslint基本使用到这就结束了,相信对eslint有一定的了解,甚至自己还能制定规则了吧。如感觉文章有点啰嗦,或介绍的不得要领的话,还请见谅。如有不对地方欢迎指出~