实践:ESLint在Vue项目中的使用

12,573 阅读11分钟

一、什么是ESlint、有什么特性

描述:

ESLint是一个集代码审查和修复的工具,它的核心功能是通过配置一个个规则来限制代码的合法性和风格

特性:

1. 发现问题: ESLint静态分析代码以快速发现问题。ESLint内置于大多数文本编辑器中,您可以将ESLint作为持续集成管道的一部分运行

2. 自动修复: ESLint发现的许多问题可以自动修复。ESLint修复程序具有语法意识,因此您不会遇到传统查找和替换算法引入的错误

3. 定制: 预处理代码,使用自定义解析器,并编写与ESLint内置规则一起使用的自己的规则。您可以自定义ESLint,使其完全按照项目所需的方式工作

二、ESlint使用及配置

基本使用:

安装

npm install eslint --save-dev

初始化配置文件,根目录生成.eslintrc.js

npx eslint --init

两种配置方式:

  • 配置注释:使用JavaScript注释把配置信息直接嵌入到一个代码源文件中
  • 配置文件:1. 使用 JavaScript、JSON 或者 YAML 文件为整个目录(处理你的主目录)和它的子目录指定配置信息。可以配置一个独立的 .eslintrc.* 文件,或者直接在 package.json 文件里的 eslintConfig 字段指定配置,ESLint 会查找和自动读取它们,再者,你可以在命令行运行时指定一个任意的配置文件。

具体配置字段:

1. parser解析器及解析参数

解析器将源代码转换为称为抽象语法树(AST)的数据格式,然后,插件使用这种数据格式围绕代码的外观或行为创建称为lint规则的断言。

ESLint附带了一个内置的解析器(称为espree),因此如果你只编写标准JavaScript,就不需要自定义解析器了

如果我们想支持非标准JavaScript语法,我们需要做的就是为ESLint提供一个可供使用的替代解析器。根据工程的实际情况,对解析器进行设置,比如基于vue框架的工程需要用到能解析vue语法解析器;再比如使用到TypeScript的工程,需要配置能解析TypeScript的解析器

这里可以类比webpack,自身只能处理js、及json文件,css、html等文件需要通过自定义loader处理来理解

常用解析器:

解析参数parserOption:

{ 
    // 解析器,默认espree 
    parser: "espree", 
    parserOption: { 
        // 指定要使用的ECMAScript版本,默认值5,可以使用 6、7、8、9 或 10 来指定你想要使用的 ECMAScript 版本。你也可以用使用年份命名的版本号指定为 2015(同 6),2016(同 7),或 2017(同 8)或 2018(同 9)或 2019 (same as 10)
        ecmaVersion: 5, 
        // 设置为 "script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)
        sourceType: "module", 
        // 这是个对象,表示你想使用的额外的语言特性,所有选项默认都是 false
        ecmafeatures: { 
            // 是否允许在全局作用域下使用 return 语句 
            globalReturn: false, 
            // 是否启用全局 strict 模式(严格模式) 
            impliedStrict: false, 
            // 是否启用JSX,支持 JSX 语法并不等同于支持 React。React 对 ESLint 无法识别的JSX语法应用特定的语义。如果你正在使用 React 并且想要 React 语义支持,我们建议你使用 [eslint-plugin-react](https://github.com/yannickcr/eslint-plugin-react)。
            jsx: false, 
            // 是否启用对实验性的objectRest/spreadProperties的支持
            experimentalObjectRestSpread: false 
        } 
    },
}
2. env环境

一个环境定义了一组预定义的全局变量

指定不同的环境可以给对应环境下提供预设的全局变量,比如说在 browser 环境下,可以使用 window 全局变量;在 node 环境下,可以使用 process 全局变量等。 可用的环境包括: 可选配置项如下:

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

这些环境并不是互斥的,所以可以同时定义多个。可以在源文件里、在配置文件中或使用 命令行 的 --env 选项来指定环境。

3. globals全局变量

脚本在执行期间访问的额外的全局变量

当访问当前源文件内未定义的变量时,no-undef 规则将发出警告。如果你想在一个源文件里使用全局变量,在Globals中定义这些全局变量,这样ESLint就不会发出警告了

"globals": {
        "var1": "writable", // "off" 禁用全局变量
        "var2": "readonly"
    }
4. rules规则

启用的规则及其各自的错误级别,配置文件

ESLint 附带有大量的规则,要改变一个规则设置,你必须将规则ID设置为下列值之一:

  • "off" 或 0 - 关闭规则
  • "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
  • "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
"rules": {
        "eqeqeq": "off", // 要求使用 `===` 和 `!==`
        "curly": "error", // 强制所有控制语句使用一致的括号风格
        "quotes": ["error", "double"] // 引号
    }
5. extends配置扩展

实际项目中配置rules的时候,不可能团队一条一条的去商议配置,太费精力了。通常的做法是使用业内大家普通使用的、遵循的编码规范;然后通过extends去引入这些规范。extends配置的时候接受字符串或者数组

  • 指定配置的字符串(配置文件的路径、可共享配置的名称、eslint:recommended 或 eslint:all)
  • 字符串数组:每个配置继承它前面的配置

extends可以理解为rules的快捷配置字段,一般先配置extends为业内通用规范,且数组时后面的会覆盖前面的,并自定义配置rules覆盖extends中不满足你想要规范的规则

{
    "extends": [
        "eslint:recommended",
        "plugin:vue/essential", // 实际npm包插件eslint-config-vue/essential [插件名:配置名]
        "airbnb-base", // 实际npm包插件eslint-config-vue/airbnb-base
        "@vue/prettier",
        "./node_modules/coding-standard/.eslintrc-es6"
    ]
}

从上面的配置,可以知道extends支持的配置类型可以是以下几种

  • eslint开头的:是ESLint官方的扩展;常见配置eslint:recommendedeslint:all
  • plugin开头的:是插件类型扩展,可以省略包名的前缀 eslint-plugin-,比如 plugin:vue/essential,实际上使用的是eslint-config-vue插件,而essential是配置名,可见插件配置说明,如下图,包eslint-config-vue中定义了配置参数essential

image.png

  • eslint-config开头的:来自npm包,使用时可以省略前缀eslint-config-,比如上面的直接写成airbnb-base
  • @开头的:扩展和eslint-config一样,只是在npm包上面加了一层作用域scope
  • 一个执行配置文件的相对路径或绝对路径;

常用extends配置:

  • eslint:recommended:ESLint内置的推荐规则,属性启用一系列核心规则,这些规则报告一些常见问题,在 规则页面 中被标记为✅
  • eslint:all:ESLint内置的所有规则;
  • eslint-config-airbnb-base:airbnb的JS规范;
  • eslint-config-standard:standard的JS 规范;
6. plugins插件

ESLint虽然可以定义很多的rules,以及通过extends来引入更多的规则,但是说到底只是检查JS语法。如果需要检查Vue中的template或者React中的jsx,就束手无策了。所以引入插件的目的就是为了增强ESLint的检查能力和范围。

在配置文件里配置插件时,可以使用 plugins 关键字来存放插件名字的列表。插件名称可以省略 eslint-plugin- 前缀。

{
    "plugins": [
        "vue", // 等价于"eslint-plugin-vue"
        "@typescript-eslint" // 等价于@typescript-eslint/eslint-plugin
    ]
}
7. 其他配置

配置当前目录为 root

ESLint检测配置文件步骤:

  1. 在要检测的文件同一目录里寻找 .eslintrc.*package.json
  2. 紧接着在父级目录里寻找,一直到文件系统的根目录;
  3. 如果在前两步发现有 root:true 的配置,停止在父级目录中寻找 .eslintrc
  4. 如果以上步骤都没有找到,则回退到用户主目录 ~/.eslintrc 中自定义的默认配置;

通常我们都习惯把 ESLint 配置文件放到项目根目录,因此可以为了避免 ESLint 校验的时候往父级目录查找配置文件,所以需要在配置文件中加上 root: true。

{
    "root": true,
}

三、ESlint校验

第二块配置完了配置文件,但是怎么校验文件呢

校验.js类型文件

// 校验 a.js 和 b.js 
npx eslint a.js b.js 
// 校验 src 和 scripts 目录 
npx eslint src scripts

校验其他类型文件

通常ESLint只能校验JS文件。比如需要校验.vue文件,光配置vue插件vue-eslint-parser解析器是不够的,还需要让ESLint在查找文件的时候找到.vue文件。ESLint提供了--ext来指定具体需要校验的文件

npx eslint --ext .js,.vue src

自动修复部分校验错误的代码

rules列表项 中标识了🔧规则表示该规则是可以自动修复的,ESLint提供了--fix image.png

package.json配置scripts

{ 
    "scripts": { 
        "lint": "npx eslint --ext .js,.vue src", 
        "lint:fix": "npx eslint --fix --ext .js,.vue src", 
    } 
}

过滤一些不需要校验的文件

对于一些公共的JS、测试脚本或者是特定目录下的文件习惯上是不需要校验的,因此可以在项目根目录通过创建一个.eslintignore文件来配置,告诉ESLint校验的时候忽略它们:

public/
src/main.js

四、为什么要用ESLint

1、背景:

总结为两点:

  • 保持代码风格一致:一千个程序员,就有一千种代码风格。在前端开发中,有几个至今还在争论的代码风格差异。如果一个工程代码风格不一样,可以想象随着项目迭代扩大,简直不忍直视

    • 单引号还是双引号?
    • 代码行结束是否需要分号?
    • 两个空格还是四个空格?
  • 减少代码出错几率:由于JavaScript 的灵活性,往往一段代码能有多种写法,这时候也会导致协同时差异。并且,有一些写法可能会导致不易发现的 bug,或者这些写法的性能不好,开发时也应该避免

为了解决这类静态代码问题,每个团队都需要一个统一的JavaScript代码规范,团队成员都遵守这份代码规范来编写代码。当然,靠人来保障代码规范是不可靠的,需要有对应的工具来保障,ESLint就是这个工具

2、为什么不是Prettier

有的读者看到这里,可能会说:Prettier也可以保证代码风格一致。是的Prettier确实可以按照设置的规则对代码进行统一格式化,但是需要明确的一点是,Prettier只会在格式上对代码进行格式化,一些隐藏的代码质量问题Prettier是无法发现的,而ESLint可以。

3、目标

开发时提示,保存时自动修复,提交时检测

五、项目实践

1、vue-cli创建工程

// package.json
 "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "babel-eslint": "^10.1.0",
    "eslint": "^6.7.2",
    "eslint-plugin-vue": "^6.2.2",
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential", // 等价于用到eslint-plugin-eslint/essential
      "eslint:recommended",
    ],
    "parserOptions": {
      "parser": "babel-eslint" // 解析器
    },
    "rules": {}
  },

2、在VSCode中支持ESLint

前面做的配置,都需要执行命令才能进行检查和修复代码,还是挺不方便的,如果我希望编辑完或者保存时去检查代码该如何做呢?可以直接在IDE里安装ESLint插件

  • 在 VSCode 左下角找到一个齿轮 ⚙ 图标,点击后选择设置选项,这个时候打开了设置面板;
  • 然后在 VSCode 右上角找到打开设置(json)的图标,点击后,会打开 settings.json 文件;
  • 然后把以下配置贴进去即可;
{
    "eslint.alwaysShowStatus": true,  // 总是在 VSCode 显示 ESLint 的状态
    "eslint.quiet": true,             // 忽略 warning 的错误
    "editor.codeActionsOnSave": {     // 保存时使用 ESLint 修复可修复错误
        "source.fixAll": true,
        "source.fixAll.eslint": true
    }	
}

3、pre-commit

两个背景

  • 以上只是通过ESLint自动修复能够修复的错误以代码的格式化,但是在实际开发的时候难免会遇到无法fix的错误,可能开发人员也忘记修改,如果这个时候把代码提交到远程仓库,那就把糟糕的代码给提交上去了
  • 使用命令修复的时候,不小心修改了他人代码,很容易造成冲突。如果一个项目以前没有用过 linter,如何最方便地开始使用并且尽量不改动之前的代码?

解决以上问题的一个方案就是,在提交代码的时候,自动修复格式问题,并且只修复自己改动的代码

可以通过配置git hookspre-commit钩子来实现这个目的。主要是利用了huskylint-staged这 2 个包。

  • husky:用来配置 git hooks
  • lint-staged:拿到staged文件进行处理
 "lint-staged": {
    "**/*.{js,vue}":  [
      "eslint --fix",
      "git add"
    ],
    "**/*.{less,css,vue}":  [
      "stylelint --config  ./.stylelintrc --fix",
      "git add"
    ]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  }

参考