从零到一搭建 react 项目系列之(十三)

原先打算将 ESLint、Prettier 放到最后一个环节介绍的,但由于不想再写示例案例的时候,还要手动格式化,真的会逼死强迫症的人呐!

好吧,我有强迫症。。。

关于 ESLint、Prettier 的内容还是挺多的,所以本文篇幅较长。

一、简介

ESLint

ESLint 最初是由 Nicholas C. Zakas 于 2013 年 6 月创建的开源项目。ESLint 凭借插件化、配置化、可满足不同的技术栈的个性需求打败了 JSHint 成为最受欢迎的 JavaScript 代码检测工具。 👉 中文官网

从 JSLint 到 ESLint,经历了什么,他们各有什么特点,看这篇文章 👉 JS Linter 进化史

恰恰正是因为 ESLint 推崇配置化,往往需要配置很多繁杂的 rules 规则,如果每个人都要这种做的话,显然会耗费很多精力。于是就有人站了出来,并在 GitHub 上开源了他们的代码规范库,比较流行的有 airbnb、standard、prettier 等。

但在这里我选择的是国内腾讯 AlloyTeam 团队出品的 eslint-config-alloy 开源规范库。

其实他们团队最开始使用 Airbnb 规则,但是由于它过于严格,部分规则还是需要个性化,导致后来越改越多,最后决定重新维护一套。经过两年多的打磨,现在 eslint-config-alloy 已经非常成熟了。

我选择它的几点原因:

  • 适用于 React/Vue/Typescript 项目
  • 样式相关规则由 Prettier 管理
  • 中文文档和网站示例(鄙人蹩脚的外语水平,这点极吸引我,哈哈)
  • 更新快,及时跟进最新规则和废弃规则,且拥有官方维护的 Vue、Typescript、React + Typescript 规则
Prettier

An opinionated code formatter.

Prettier 是一个代码格式化工具,相比于 ESLint 中的代码格式规则,它提供了更少的选项,但是却更加专业,且与大多数编辑器集成。

它要解决的就是类似于使用两个空格,还是四个空格的争论。在团队开发中达成统一。

支持以下语言:


二、ESLint

接下来介绍本项目是如何配置它们的。

此前我写了一篇关于小程序项目配置 ESLint、Prettier、Git 提交规范的文章,其实是大同小异,可以去看下 👉 点这里

1. ESLint 的安装

必要条件:

  • Node.js 6.14+
  • npm 3+(or yarn)
    *个人建议 npm 版本大于 5.2 以上,可使用 npx 命令。
# 全局安装(建议本地项目安装)
$ yarn global add eslint
# 创建 .eslintrc 配置文件
$ eslint --init
# 检测某个或多个文件(支持 glob 匹配模式,如 eslint lib/** )
$ eslint file1.js file2.js


# 华丽的分割线 ****************************************************


# 本地项目安装(推荐)
$ yarn add --dev eslint@6.7.1
# 以下同时安装了一些 ESLint 插件或者与 Prettier 相关的依赖包
$ yarn add --dev babel-eslint@10.0.3
$ yarn add --dev eslint-config-alloy@3.7.1
$ yarn add --dev eslint-plugin-react@7.18.3
$ yarn add --dev prettier@2.0.5
$ yarn add --dev prettier-eslint-cli@5.0.0
#
# 创建 .eslintrc 配置文件
#(不支持 npx 就使用 ./node_modules/.bin/eslint --init ,下同)
$ npx eslint --init
# or
$ yarn eslint --init
#
# 检测文件
$ npx eslint file1.js file2.js
# or
$ yarn eslint file1.js file2.js

我就直接在项目根目录添加一个 ESLint 的配置文件 .eslintrc.js,不用命令行生成了。

// .eslintrc.js
module.exports = {
  extends: [
    'alloy'
  ],
  env: {
    // 你的环境变量(包含多个预定义的全局变量)
    //
    // browser: true,
    // node: true,
    // mocha: true,
    // jest: true,
    // jquery: true
  },
  globals: {
    // 你的全局变量(设置为 false 表示它不允许被重新赋值)
    //
    // myGlobal: false
  },
  rules: {
    // 自定义你的规则
  }
}

还有一种方式,使用 JavaScript 注释吧配置信息直接嵌入到一个代码源文件中。可以看下这篇文章

2. 介绍 ESLint 的几个配置项
  • 解析器(Parser)

ESLint 默认使用 Espree 作为其解析器,你可以在配置文件中指定一个不同的解析器。(需单独安装解析器包)

{
  parser: 'babel-eslint'
}

注意,在使用自定义解析器时,为了让 ESLint 在处理非 ES5 特性时正常工作,配置属性 parserOptions 仍然是必须的。解析器会被传入 parserOptions,但是不一定会使用它们来决定功能特性的开关。

  • 解析器选项(Parser Options)

ESLint 允许你指定你想要支持的 JavaScript 语言选项。默认情况下,ESLint 支持 ES5 语法。你可以覆盖该设置,以启用对 ECMAScript 其它版本和 JSX 的支持。

{
  parserOptions: {
    ecmaVersion: 10, // 指定 ECMAScript 版本,默认为3,5。同样支持使用年份命名的版本号指定为 2015(同 6),2016(同 7),或 2017(同 8)或 2018(同 9)或 2019 (same as 10)
    sourceType: 'module', // 设置为 "script" (默认) 或 "module"
    ecmaFeatures: { // 表示你想使用的额外的语言特性
      jsx: true // 启用 JSX
      // 还有 globalReturn、impliedStrict、experimentalObjectRestSpread 等选项
    }
  }
}

设置解析器选项能帮助 ESLint 确定什么是解析错误,所有语言选项默认都是 false

  • 处理器(Processor)

这个个人平常几乎不使用,所以不展开细说,请看官方介绍

  • 环境(Environments)

一个环境定义了一组预定义的全局变量。这些环境并不是互斥的,所以你可以同时定义多个。

  • browser - 浏览器环境中的全局变量。
  • node - Node.js 全局变量和 Node.js 作用域。
  • commonjs - CommonJS 全局变量和 CommonJS 作用域 (用于 Browserify/Webpack 打包的只在浏览器中运行的代码)。
  • es6 - 启用除了 modules 以外的所有 ES6 特性(该选项会自动设置 ecmaVersion 解析器选项为 6)。
  • worker - Web Workers 全局变量。
  • jquery - jQuery 全局变量。
  • 更多...
{
  plugins: ['example']
  env: {
    browser: true,
    node: true,
    es6: true,
    'example/custom': true // 使用插件(不带前缀) example 中的 custom 环境
  }
}
  • 全局变量(Globals)

当访问当前源文件内未定义的变量是,no-undef 规则将发出警告。前面提到环境时,设置某个环境时会定义一组对应的全局变量。

{
  globals: {
    // 你的全局变量(设置为 false 表示它不允许被重新赋值)
    // myGlobal: false
  }
}

由于历史原因,布尔值 false 和字符串值 "readable" 等价于 "readonly"。类似地,布尔值 true 和字符串值 "writeable" 等价于 "writable"。但是,不建议使用旧值。

使用字符串 "off" 禁用全局变量。假如当前环境不支持使用 Promise 可以通过 "Promise": "off" 全局禁用。

  • 插件(Plugins)

ESLint 支持使用第三方插件。在使用插件之前,你必须使用 npm 安装它。插件名称可以省略 eslint-plugin- 前缀。

{
  plugins: [
    // 相当于 'eslint-plugin-prettier'
    'prettier'
  ]
}
  • 规则(Rules)

ESLint 附带有大量的规则。你可以使用注释或配置文件修改你项目中要使用的规则。要改变一个规则设置,你必须将规则 ID 设置为下列值之一:

  • "off"0 - 关闭规则
  • "warn"1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
  • "error"2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
{
  plugins: ['plugin1']
  rules: {
    'no-alert': 2,
    'no-eval': 2,
    'plugin1/rule1': 2,
    indent: ['error', 2, { SwitchCase: 1 }]
  }
}

若要禁用一组文件的配置文件中的规则,请使用 overridesfiles 配合使用。

{
  rules: {...},
  overrides: [
    {
      files: ['*-test.js', '*.spec.js'],
      rules: {
        'no-unused-expressions': 0
      }
    }
  ]
}

在你的文件中使用行注释或者块注释的方式来禁止(某些)规则出现警告,可以看这篇文章,里面有详细介绍。

  • 扩展(Extends)

它的属性值可以是:

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

eslint:recommended

ESLint 所有的规则默认都是禁用的。在配置文件中,使用 "extends": "eslint:recommended" 来启用推荐的规则,报告一些常见的问题,在规则页面中这些推荐的规则都带有一个 ✅ (对勾)标记。

它只能在 ESLint 主要版本进行更新。换句话说,假如 ESLint 6.7.1 版本的规则 ruleA6.8.0 不会更新,只有在 ESLint 7.x 或更高才可能会更新。所以在更新 ESLint 主版本之后,在使用 --fix 选项继续修复之前,应该先检查一下报告的问题,这样你就知道哪些规则有调整了。

eslint:all(不推荐使用)

它启用当前安装的 ESLint 中所有的核心规则,它可以在 ESLint 的任何版本进行更改,使用有风险。

可共享的配置

它是一个 npm 包,输出一个配置对象。属性值可省略包名 eslint-config-,比如 "extends": "alloy"

插件

它是一个 npm 包,除了通常的输出规则之外,一些插件还可以输出一个或多个命名的 配置

  • plugins 属性值可以省略包名的前缀 eslint-plugin-.
  • extends 属性值由以下组成
  1. plugin:
  2. 包名(是省略了 eslint-plugin- 前缀,比如 react
  3. /
  4. 配置名称(比如 recommended

例如,"plugin:react/recommended"

{
  plugins: ['react'],
  extends: [
    'eslint:recommended',
    'plugin:react/recommended'
  ]
}

配置文件路径

extends 属性值可以是基本配置文件的绝对/相对路径,相对路径相对于当前配置文件的路径。

{
  extends: [
    './node_modules/coding-standard/eslintDefaults.js',
    './node_modules/coding-standard/.eslintrc-es6',
    './node_modules/coding-standard/.eslintrc-jsx'
  ]
}
  • 覆盖(Overrides)

比如,如果同一个目录下的文件需要有不同的配置。因此,你可以在配置中使用 overrides 键,它只适用于匹配特定的 glob 模式的文件。

几点要注意的:

  • 只能在 .eslintrc.* 或者 package.json 中配置。
  • 采用相对路径,相对于配置文件的路径。
  • Glob 模式覆盖要比其他常规配置具有更高的优先级。同一配置文件中多个覆盖按照顺序被应用,即最后一个覆盖会有最高优先级。
{
  rules: {
    quotes: ['error', 'double']
  },
  overrides: [
    {
      files: ['bin/*.js', 'lib/*.js'],
      excludedFiles: '*.test.js',
      rules: {
        quotes: ['error', 'single']
      }
    }
  ]
}
3. ESLint 配置文件格式

ESLint 支持几种格式的配置文件:

  • JavaScript - 使用 .eslintrc.js 然后输出一个配置对象。
  • YAML - 使用 .eslintrc.yaml.eslintrc.yml 去定义配置的结构。
  • JSON - 使用 .eslintrc.json 去定义配置的结构,ESLint 的 JSON 文件允许 JavaScript 风格的注释。
  • (弃用) - 使用 .eslintrc,可以使 JSON 也可以是 YAML。
  • package.json - 在 package.json 里创建一个 eslintConfig 属性,在那里定义你的配置。

注意:如果同一个目录下多个配置文件,ESLint 只会使用一个

优先级从高到低

  1. .eslintrc.js
  2. .eslintrc.yaml
  3. .eslintrc.yml
  4. .eslintrc.json
  5. .eslintrc
  6. package.json
4. ESLint 的层叠配置

*下面介绍的配置文件采用 JavaScript 格式,即 .eslintrc.js

假如如下场景,项目根目录有一个 .eslintrc.js 配置文件,test/ 目录也有一个配置文件。

your-project
├── .eslintrc.js
├── lib
│ └── source.js
└─┬ tests
  ├── .eslintrc
  └── test.js

这种情况 ESLint 如何处理呢?

层叠配置使用离检测文件最近的 .eslintrc.js 文件作为最高优先级,然后才是父目录里的配置文件。

当 ESLint 遍历 lib/ 目录时,使用根目录里的 .eslintrc.js 作为它的配置文件。当遍历到 tests/ 目录时,除了会使用根目录 your-project/.eslintrc.js 之外,还会用到 your-project/tests/.eslintrc.js ,所以 your-project/tests/test.js 是基于它的目录层次结构中的两个配置文件的组合,并且离的最近的一个优先。通过这种方式,你可以有项目级 ESLint 设置,也有覆盖特定目录的 ESLint 设置。

完整的配置层次结构,从最高优先级到最低的优先级,如下:

  1. 行内配置
    1. /* eslint-disable *//* eslint-enable */
    2. /* global */
    3. /* eslint */
    4. /* eslint-env */
  2. 命令行选项(或者 CLIEngine 等价物)
    1. --global
    2. --rule
    3. --env
    4. -c--config
  3. 项目级配置:
    1. 与检测的文件在同一目录下的 .eslintrc.* 或者 package.json 文件。
    2. 继续在父级目录寻找 .eslintrc.*package.json 文件,直到根目录(包含)或直到发现一个有 "root": true 的配置。
  4. 如果不是(1)到(3)中的任何一种情况,则退回到 ~/.eslintrc(用户目录下) 中自定义的默认配置。

非常有必要的是,在项目根目录下设置一个 "root": true,表示 ESLint 一旦发现配置文件中有该属性时,它就会停止在父级目录中寻找。

{
  root: true
}
5. 检测扩展名

目前只能通过命令行选项 --ext 指定,告诉 ESLint 哪个文件扩展名要检测。

// package.json
{
  "scripts": {
    "eslint": "eslint . --ext .js"
  }
}
6. 忽略特定的文件和目录

通过项目根目录创建一个 .eslintignore 文件告诉 ESLint 去忽略特定文件或目录。它依照 .gitignore 规范

如果相比于当前目录下 .eslintignore 文件,你更想使用一个不同的文件,你可以在命令行使用 --ingnore-path 选项指定它。例如,你可以使用 .jshintignore 文件,它有相同的格式。

$ npx eslint --ignore-path .jshintignore file.js

如果没有发现 .eslintignore 文件,也没有指定替代文件,ESLint 将在 package.json 文件中查找 eslintIgnore 键,来检查要忽略的文件。

重要:

  1. 注意代码库的 node_modules 目录,比如,一个 packages 目录,默认情况下不会被忽略,需要手动添加到 .eslintignore
  2. 指定 --ignore-path 意味着任何现有的 .eslintignore 文件将不被使用。

附上我的 .eslintrc.js 配置文件

module.exports = {
  root: true,
  parser: 'babel-eslint',
  extends: [
    'alloy',
    'alloy/react' // eslint-config-alloy 启用 eslint-plugin-react
  ],
  parserOptions: {
    ecmaVersion: 2019,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true // 启用 JSX
    }
  },
  settings: {
    react: {
      version: 'detect' // 自动选择你已安装的版本
    }
  },
  // 插件名称可以省略 eslint-plugin- 前缀。
  plugins: [],
  // 环境变量(包含多个预定义的全局变量)
  env: {
    browser: true,
    es6: true,
    node: true,
    commonjs: true
  },
  // 全局变量(设置为 false 表示它不允许被重新赋值)
  globals: {},
  // 自定义规则
  rules: {
    'react/prop-types': [0],
    'default-case-last': 0,
    'no-unused-vars': 0,
    'no-var': 0,
    'no-irregular-whitespace': 0,
    'use-isnan': 2,
    'no-alert': 2,
    'no-eval': 2,
    'spaced-comment': 2,
    'react/self-closing-comp': 0,
    indent: ['error', 2, { SwitchCase: 1 }]
  }
}

三、Prettier

终于讲完 ESLint 了,内容挺多的,差点吐了...接着介绍 Prettier。

  1. 首先安装 Prettier
$ yarn add --dev prettier@2.0.5
$ yarn add --dev prettier-eslint-cli@5.0.0
  1. 格式化文件
$ yarn prettier --write [dir or file]

# 格式化全部文件
# yarn prettier --write .
# 格式化确切的目录,如 app
# yarn prettier --write app/
# 格式化确切的文件,如 index.js
# yarn prettier --write app/index.js
# 支持 Glob 模式匹配文件,如格式化 app 目录下的所有 JS 扩展文件
# yarn prettier --write "app/**/*.js"
  1. 检查文件
# 匹配方式同上
$ yarn prettier --check [dir or file]

--check--write 不同的是,前者仅检查文件是否已被格式化,后者是格式化并覆盖。

  1. 添加 Prettier 配置文件 .prettierrc.js,以及相关规则。
    下面是个人比较喜欢的配置,若想知道更多可选配置,请移步官方文档
// .prettierrc.js
module.exports = {
  // 与 ESLint 整合
  // eslintIntegration: false,
  // 一行最多 160 字符
  printWidth: 160,
  // 使用 2 个空格缩进
  tabWidth: 2,
  // 不使用缩进符,而使用空格
  useTabs: false,
  // 行尾不需要有分号
  semi: false,
  // 使用单引号(JSX 引号会忽略此选项)
  singleQuote: true,
  // JSX 不使用单引号,而使用双引号
  jsxSingleQuote: false,
  // 对象的 key 仅在必要时用引号
  quoteProps: 'as-needed',
  // 末尾不需要逗号
  trailingComma: 'none',
  // 大括号内的首尾需要空格
  bracketSpacing: true,
  // JSX 标签的反尖括号需要换行
  jsxBracketSameLine: false,
  // 箭头函数,只有一个参数的时候,不需要括号
  arrowParens: 'avoid',
  // 每个文件格式化的范围是文件的全部内容
  rangeStart: 0,
  rangeEnd: Infinity,
  // 不需要写文件开头的 @prettier
  requirePragma: false,
  // 不需要自动在文件开头插入 @prettier
  insertPragma: false,
  // 使用默认的折行标准
  proseWrap: 'preserve',
  // 根据显示样式决定 HTML 要不要折行
  htmlWhitespaceSensitivity: 'css',
  // 换行符使用 lf
  endOfLine: 'lf'
}
  1. 关于 overrides 选项

上面的可选项,除了通过配置文件的形式指定,也可以通过 CLI 形式来指定,但推荐前者。而 overrides 选项只能在配置文件中指定。

overrides 的作用是对某些文件扩展名,文件夹和特定文件进行不同的配置

例如,Prettier 的默认解析器是不支持解析小程序中扩展名为 .wxss.acss 的文件的,那么我们就可以利用 overrides 来指定解析器,然后就能对其进行格式化了。

{
  overrides: [
    {
      files: ['*.wxss', '*.acss'],
      options: {
        parser: 'css'
      }
    },
    // 类似地,如果有需要的话,亦可将 JavaScript 文件使用 flow 来代替默认的 babel 解析器。
    // {
    //   files: '*.js',
    //   options: {
    //     parser: 'flow'
    //   }
    // }
  ]
}
  1. 共享配置

Prettier 提供了一个共享配置(Sharing configurations)的选项。

它适用于什么场景呢?

假如我们有一份 Prettier 配置,同时适用于我们公司多个项目,那么我们就可能需要用到它,这样我们只需要维护一套配置文件就好了。类似于 NPM 包一样,但这里不赘述,有需要的看下官方文档介绍,后续我会考虑单独写一篇文章介绍,到时会回来更新文章的。

  1. 忽略文件 .prettierignore

它同样依照 .gitignore 的语法,没什么好说的,根据项目自行增删改。

# .prettierignore 文件配置
/node_modules
/dist
/src/fonts/

## OS
.DS_Store
.idea
.editorconfig
package-lock.json
.npmrc

# Ignored suffix
*.log
*.md
*.svg
*.png
*ignore


## Built-files
.cache
dist

四、ESLint + Prettier

1. 有必要了解的两个依赖

ESLint 解决的是代码质量问题,而 Prettier 解决的是代码风格问题。按道理 ESLint + Prettier 结合就能解决前面两个问题,但实际上两者一起使用的时候会有冲突,原因是 ESLint 也有参与代码格式问题。

所以,我们需要以下两个依赖包来处理冲突:

关闭所有与 Prettier 冲突的 ESLint 规则。(被关闭的规则是与代码风格相关的)

{
  extends: ['prettier'] // eslint-config-prettier 一定要是最后一个,才能确保覆盖其他配置
}

将 Prettier 作为 ESLint 规则运行,并将差异报告为单个 ESLint 问题。

使用了 eslint-config-prettier 关闭掉与 Prettier 冲突的规则,这时格式问题已全面交给 Prettier 处理,为什么还需要 eslint-plugin-prettier 呢?

原因是这样的,我们期望报错的来源依旧是 ESLint。这个插件把 Prettier 格式配置以 ESLint rules 规则的方式写入,这样所有的报错都来自于 ESLint 了。

{
  plugins: ['prettier'],
  rules: {
    'prettier/prettier': 'error'
  }
}

上面两者配置的结合就相当于(官方推荐):

{
  extends: ['plugin:prettier/recommended']
}

其实本项目的配置并不使用以上两个依赖,但我认为,非常有必要清楚了解两个插件的作用。

既然如此,那我是怎么处理 ESLint 和 Prettier 两者的冲突呢?

2. 解决方案

原因其实跟我选用的 eslint-config-alloy 有关。eslint-config-alloy 从 v3 开始,已经不包含所有样式相关的规则了,故不需要引入 eslint-config-prettier

虽然官方介绍说,不包含任何的样式相关的规则,但是我发现在使用的过程中,ESLint 与 Prettier 仍然存在一些冲突,比如三元运算的缩进问题。

这是我抛出的一个疑惑,不知道是我理解错了,还是什么原因?后续打算提个 issues 问下大佬。

我的 NPM 脚本是这样设计的:

{
  "scripts": {
    "eslint": "eslint . --ext .js",
    "eslint:fix": "eslint --fix . --ext .js",
    "prettier:fix": "prettier --config .prettierrc.js --write './**/*.{js,css,less,scss,json}'",
    "format:all": "npm-run-all -s prettier:fix eslint:fix"
  }
}

看到上面这个,你们大致也清楚思路了。既然 ESLint 与 Prettier 仍存在冲突,那么两者存在冲突时,我就以 ESLint 的优先级最高就好了。利用 npm-run-all 按顺序分别执行 prettier:fixeslint:fix 命令,这样只要执行 yarn run format:all 一条命令就把代码质量检查与代码风格都检查处理一遍(包含了一些自动修复的)。

五、EditorConfig

EditorConfig 有助于维护跨多个编辑器和 IDE 从事同一项目的多个开发人员的一致编码风格。 EditorConfig 项目包含一个用于定义编码样式的文件格式和一个文本编辑器插件集合,这些文本编辑器插件使编辑器可以读取文件格式并遵循定义的样式。 EditorConfig 文件易于阅读,并且可以与版本控制系统很好地协同工作。

它主要是用于规范缩进风格,缩进大小,Tab 长度以及字符集等,解决不同 IDE 的编码范设置。EditorConfig 插件会去查找当前编辑文件的所在文件夹或其上级文件夹中是否有 .editorconfig 文件。如果有则编辑器的行为会与 .editorconfig 文件中定义的一致,并且其优先级高于编辑器自身的设置。

使用 VS Code 进行开发的话,搜索安装 EditorConfig for VS Code 插件。

在项目根目录添加一份 .editorconfig 配置文件。

# .editorconfig

# 根目录的配置文件,编辑器会由当前目录向上查找,如果找到 `roor = true` 的文件,则不再查找
root = true

# 匹配所有的文件
[*]
# 缩进风格:space
indent_style = space
# 缩进大小 2
indent_size = 2
# 换行符 lf
end_of_line = lf
# 字符集 utf-8
charset = utf-8
# 不保留行末的空格
trim_trailing_whitespace = true
# 文件末尾添加一个空行
insert_final_newline = true
# 运算符两遍都有空格
spaces_around_operators = true

# 对所有的 js 文件生效
[*.js]
# 字符串使用单引号
quote_type = single
trim_trailing_whitespace = true

[.*rc]
indent_size = 2
indent_style = space

[*.json]
indent_size = 2
indent_style = space

[*.md]
indent_style = space
trim_trailing_whitespace = false

六、关于 eslint-loader 和 babel-eslint

1. eslint-loader

我们希望在项目开发过程中,对每次修改代码都能够自动进行 ESLint 的检查。这样,倘若编写代码时出现了语法错误等问题,我们能够迅速定位问题并解决,所以我们需要借助 eslint-loader 来帮我们完成这个需求。

$ yarn add --dev babel-loader@4.0.2
// webpack.config.js
{
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: 'babel-loader'
      },
      {
        test: /\.js$/,
        enforce: 'pre', // 确保要比 babel-loader 执行,因为 eslint-loader 要检测的是 babel 之前的代码
        exclude: /node_modules/,
        loader: 'eslint-loader',
        options: {
          fix: true, // 启用 ESLint autofix 自动修复,注意此选项将更改源文件。
          cache: true
        }
      }
    ]
  }
}

需要注意的是,我们使用 eslint-loader 检查的是我们编写的源码,而不是经过 Babel 转译后的代码,所以我们要确保在被 Babel 转译之前使用它。

两种方法:

  1. 严格按照上面 👆 配置文件中 rules 的顺序,eslint-loader 一定要放在 babel-loader 后面,因为 Loader 的加载顺序是“从下往上(从右往左)”
  2. eslint-loaderRule.enforce 属性设置为 pre,以前置处理。这样配置编写顺序可在 babel-loader 或前或后了。(为了安全起见,推荐这种写法)

温馨提示:官方指出 eslint-loader 已弃用,被 eslint-webpack-plugin 取代,后者解决了前者的一些已知问题。(若使用最新版,建议用后者)

2. babel-eslint

上面讲述 ESLint 的时候,我使用的解析器是 babel-eslint,而不是默认的 Espree

为什么使用它作为 ESLint 的解析器呢?

原因是这样的,ESLint 的默认解析器和核心规则仅支持最新的 ECMAScript 标准,不支持 Babel 提供的实验性(例如新功能)和非标准(例如 Flow 或 TypeScript 类型)语法。 babel-eslint 是允许 ESLint 在 Babel 转换后的源代码上运行的解析器。 注意:仅在使用 Babel 转换代码时才需要使用 babel-eslint。如果不是这种情况,请为您选择的 ECMAScript 风格使用相关的解析器(请注意,默认解析器支持所有非实验语法以及 JSX)。(eslint-babel 官方原话

而本项目就是使用了 Babel 将代码转换为向后兼容的 JavaScript 语法,所以需要用到 babel-eslint

温馨提示:babel-eslint 已移入 Babel monorepo,若使用最新版本可直接安装 @babel/eslint-parser 依赖包。

七、至此

关于 ESLint + Prettier 的内容基本就介绍完了,篇幅有点长。

但其实这里应该要结合 Git Hooks 来做一些代码提交规范与检查的事情,这样就能确保我们提交的代码都是经过代码质量检查与格式化的。

因为人总会有在提交代码前忘记进行 Code Formatting 的时候,人非圣贤,孰能无过,表示理解。假如我们设了一个“关卡”,在每次 git commit 之前都必须自动对暂存文件进行检测,只要检测不通过就不允许提交代码,这样就能有效地防止这种现象了。

以上这个做法,其实在另一系列文章介绍过(点击查看)。当然本项目后续对这块内容也还会介绍的,但会放后一点,这里篇幅也过长了,不宜再述。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,214评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,307评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,543评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,221评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,224评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,007评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,313评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,956评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,441评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,925评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,018评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,685评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,234评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,240评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,464评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,467评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,762评论 2 345

推荐阅读更多精彩内容