【前端工程化】篇六 规矩方圆-ESLint

2021/03/31 posted in  工程化
Tags:  #工程化 #eslint

字数:7543, 阅读时间:20分钟

天下从事者,不可以无法仪。无法仪而其事能成者,无有也。 -------墨子《法仪》

【前端工程化】系列文章链接:

示例代码仓库:https://github.com/BWrong/dev-tools

声明:如按照文中代码执行报错,请检查依赖版本是否和示例代码仓库中一致。

古人有云“不以规矩,不能成方圆”,看来规矩方圆之说古已有之,而在高度文明的现代社会,法制规则更加完善,只有大家遵守这些规则,我们的生活才能井井有条,社会才能稳定和谐。

万事均有规矩,编程也是如此,尤其是在多人协作的时候,遵循好的编程规范尤其重要,所以也诞生了很多的工具来做代码审查工作。这篇文章我们仅介绍ESLint,它也是目前前端最流行的代码审查工具。

概述

JavaScript是一门动态弱类型语言,虽说使用时很灵活,不过也容易出错。而Lint工具有助于我们在开发时就发现由于书写不规范导致的一些问题。

Lint工具主要解决如下问题:

  • 避免一些低级错误的发生,找出语法错误,冗余代码
  • 确保代码遵循推荐的风格,统一团队的代码规范

进化史

在Lint工具(仅指JS)的进化过程中,诞生过三个有代表性的工具:JSLint、JSHint 和 ESLint。

  • JSLint

JSLint是第一个JavaScript的Lint工具,它是由Douglas Crockford 大佬(《JavaScript 语言精粹》作者)开发,当时前端还处在萌芽阶段,一片混沌,Lint工具作用巨大。不过如作者大佬一般,JSLint极具个人风格,它不允许使用者更改规则,如果要使用它,就必须遵守全部规则。

  • JSHint

由于JSLint无法更改规则,很多人无法忍受,所以JSHint出现了,它提供了丰富的配置项,开发者可以根据自己的情况来做个性化的定制。而且它是由社区驱动,所以它出现后,用户迅速增长。早期的jQuery也是采用JSHint做代码检查。

  • ESLint

在2013年的时候,Nicholas C. Zakas (《JavaScript 高级程序设计》作者)在开发时,想在JSHint增加一条自定义处理规则,可是发现并不可行。受到PHP Linter的启发,在同年六月份的一个周末,大神就自己搞了一个Linter,这就是ESLint。这就是牛人,一言不合就造轮子。

与前面两个工具不同,ESLint是通过AST的方式对代码进行解析检测,具有很高的扩展性,所以在ES6和jsx这类东西出现后,只要有对应的解析器或插件,就可以快速支持,这是其他两个工具无法实现的。所以ESLint在ES6出现后迅速火了起来,Babel也为它提供了babel-eslint解析器,让ESLint更加流行。

在2016年,ESLint整合了和它同一时期诞生的另一个Linter工具JSCS(也是基于AST的方式),至此,ESLint坐稳了JS Linter的王座,成为了前端工程化必不可少的一个工具。

在TypeScript前期,并没有使用ESLint,而是使用了自研TSLint,但是由于其设计问题,在2019年的时候,官方放弃了TSLint,投入了ESLint的怀抱,通过为ESLint提供解析器和插件的方式来进行支持。

ESLint无疑是成功的,它的成功得益于采用了良好的架构设计:

  1. 关注点分离:解析器、核心、规则都是相对独立的,各司其职,具有良好的可维护性和可扩展性。
  2. 支持自定义规则:可以自定义规则及相关事件,给与开发者更多的扩展空间。迄今,社区已经拥有许多的规则插件,如eslint-plugin-reacteslint-plugin-vue等。
  3. 保持内核尽量简单:内核尽量保持简单,通过插件的方式进行功能扩展,核心不和任何框架、库耦合,具有较强的适应性。

关于ESLint成功的原因,Zakas也专门写了一篇文章,想了解的可以看看。

参考资料:JS Linter 进化史

ESLint

ESLint官方定义为一个用于查找并报告代码中问题的工具,并且支持部分问题自动修复。除了JSLint和JSHint类似的功能外,ESLint还有如下特点:

  • ESLint使用Espree进行JavaScript解析。
  • ESLint使用AST评估代码中的模式。
  • ESLint是完全可插拔的,每个规则都是一个插件,可以在运行时添加更多内容。

说了这么多,下面我们就一起来看下如何使用ESLint。

使用

安装

可以采用全局或者本地安装,推荐使用本地安装,后面我们也是采用此方式。

# 全局安装
npm install -g eslint
# 项目本地安装(推荐)
npm install -D eslint

安装成功后,在项目根目录执行如下命令,完成一系列设置来创建配置文件。

npx eslint --init

image-20200918112422980
image-20200918112422980

执行如上命令,会在项目根目录创建一个.eslintrc.js文件,内容如下:

module.exports = {
    'env': { // 环境设置
        'browser': true,
        'es2021': true,
        'node': true
    },
    'extends': 'eslint:recommended', // 使用官方或社区预设的规则
    'parserOptions': { // 解析器配置
        'ecmaVersion': 12,
        'sourceType': 'module'
    },
    'rules': {  // 自定义规则
        'indent': [
            'error',
            4
        ],
        'linebreak-style': [
            'error',
            'windows'
        ],
        'quotes': [
            'error',
            'single'
        ],
        'semi': [
            'error',
            'always'
        ]
    }
};

这个就是ESLint的配置文件,当然还有很多其他方式进行配置,我们在后面的配置部分会详细介绍,这里我们暂时使用这种方式。

如何使用

ESLint使用非常灵活,可以在多种场景使用,下面我们就瞧瞧。

命令行

现在创建一个文件./src/index.js

// ./src/index.js
let test = 1

然后在命令行输入命令:

npx eslint ./src/index.js

image-20200918171659654
image-20200918171659654

可以看到,ESLint给我们提示了两个错误:

  • test变量定义了,但是未使用
  • let test = 1后面缺少分号,因为在上面的配置文件中是要求始终添加分号的

这就是ESLint的第一个功能:找出并警告代码中有问题的地方。

像给代码加上分号这种小事情,其实没必要我们亲力亲为的(懒果然是程序猿的共性),ESLint提供了自动修复的功能,可以帮我们自动修复一些简单的问题。

执行命令,加上--fix参数:

npx eslint --fix ./src/index.js

image-20200918172959131
image-20200918172959131

我们可以看到,只有一个错误了,另外再看下./src/index.js

// ./src/index.js
let test = 1;

是不是自动加上分号了呢?oh~oh!,太酷了。

注意:

  1. 自动修复只能修复一些简单的问题,一般是书写格式之类的,修复不会影响代码的执行结果,如上面的第一个问题,ESLint是不知道如何修复,所以它不会处理,而直接抛出报错或警告了。
  2. 执行命令时,除了指定具体的文件外,也可以使用通配符,指定多个文件,如npx eslint ./src/**就可以检查src目录下的所有文件。

上面我们介绍了ESLint最基础的使用场景---命令行方式,这种方式除了上面的用法,还可以传入很多参数,下面列出几个常用的:

  • -c--config:指定配置文件
  • --env:指定执行环境
  • --global:定义全局变量
  • -h:查看帮助

更多用法请查看官方文档

Webpack(eslint-loader)

前面我们介绍了如何在命令行模式下的使用,在需要检测的时候必须要在命令行中执行相关命令才可以,有没有方法能够在我们启动项目的时候自动运行呢?

答案是肯定的,webpack作为当下最流行的构建工具,ESLint也为其提供了eslint-loader,以在构建的时候来做代码检查和修复。

首先需要安装eslint-loadereslint

npm install eslint-loader eslint --save-dev

然后在webpack配置中添加对应配置:

// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'eslint-loader',
        options: {
          // 这里是eslint的配置,建议是用配置文件
        },
      },
    ],
  },
  // ...
};

注意:

  1. 因为ESLint是针对我们书写的代码做检查,而不是针对其他loader编译后的代码,所以我们必须要保证eslint-loader最先执行,所以应该放在该规则的最后面,也可以使用enforce: 'pre'设置来强制设置到其他loader前面执行。
  2. eslint-loader的配置推荐放在eslint的配置文件中,而不放在loader的options中。

如上配置以后,在执行构建命令的时候,就会先执行检查并在终端输出检查结果(仅做检查,不会影响构建结果)。

image-20200922160134442
image-20200922160134442

不过,我们一般编码的时候,终端都运行在后台的,查看这些信息就必须要来回切换,甚是不便。作为一个懒癌患者,肯定是不愿意的。用过vue-cli的同学都知道,如果有错误提示,是会在浏览器弹出浮层提示的。

其实配置相当简单,不明白的自己回去看看前面webpack那部分吧。

// webpack.config.js
module.exports = {
    // ...
 	devServer: {
        overlay: true  // 默认此项为false,设置为true即可
    }
    // ...
}

image-20200922161111872
image-20200922161111872

在编辑器中使用(VSCode)

前面介绍的使用方式已经非常方便了,但是作为一个懒癌重度患者,在使用中我还是发现了一些问题:

  • 需要编译后才能发现代码中的问题,而不是书写代码的时候,所以缺乏及时性,那能在书写的时候就立即提示吗?
  • 如果是一些简单的格式问题,在保存前,能不能执行自动修复,而不用我们来操心呢?
  • 一些古老的项目并没有使用webpack来构建,在我们编码的时候,怎么给与错误提示呢?

果然懒才是生产力,一些大佬为编辑器提供了ESLint插件,完美的解决了如上的问题。

提示:下面仅介绍VSCode中的使用,其他编辑器请自行查阅使用方法。

首先安装ESLint插件,在VSCode中ctrl+p然后输入以下命令:

ext install dbaeumer.vscode-eslint

image-20200922163527375
image-20200922163527375

现在用VSCode打开前面的代码,可以看到有的代码下面会有黄色(警告)或者红色(错误)的波浪线提示,把鼠标移上去,还可以看到错误详情以及修复方案。

image-20200922163709515
image-20200922163709515

现在,我们书写代码的时候,就会立即给与提示,不用再去终端或者浏览器查看错误信息,然后再去文件中查找问题代码了。

那么,第二问题呢,一些简单的格式能不能自动修复呢?

只需要在VSCode的配置中加上如下配置,当保存文件的时候,一些简单的格式问题就会被自动修复,是不是又可以多撸几把王者农药了呢。

"editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
 }

img
img

提示:vscode-eslint是支持配置的,提供了eslint.options来设置全局配置,如果项目中没有配置,会以这里的配置兜底。

"eslint.options": {
  "root": true,
  "plugins": [],
  "env": {},
  "extends": [],
  "rules": {},
  "exclude": []
  "parserOptions": {}
},

对于一些项目,即使没有使用webpack也没有关系,只需要在项目中安装ESLint和添加对应的配置,在编写代码的时候也是能够生效的。

ESLint插件还提供了全局的方式,全局安装ESLint,并在VSCode的ESLint插件配置中放入eslint规则配置,则会对所有打开的文件生效。

如果项目中也有自己的配置,那么会执行配置合并,如果配置项有冲突,项目中的配置项拥有优先使用权,会覆盖全局的配置。

至此,ESLint常见的使用方式就介绍完了,接下来我们就来看看比较核心的东东。

配置

ESLint提供了丰富的配置项,让使用者可以根据自己的需求对其解析器环境全局规则插件进行配置。

具体这些配置项我们后面再详细介绍,先来看看如何添加配置。

配置方式

ESLint支持多种配置方式,总结起来大概分为如下几种:

  • 命令行:在执行eslint命令的时候,将配置信息通过cli提供的配置参数传入,使用比较繁琐,一般不使用此方式。
# 一些常用配置
# --env:设置环境
eslint --env browser,node file.js
eslint --env browser --env node file.js
# --global:设置全局变量
eslint --global require,exports:true file.js
eslint --global require --global exports:true
# --rule:设置规则
eslint --rule 'quotes: [2, double]'
eslint --rule 'guard-for-in: 2' --rule 'brace-style: [2, 1tbs]'
eslint --rule 'jquery/dollar-sign: 2'
# ...
  • 内联注释:将配置以注释的方式写在代码文件中(一般放在文件的最前面),由于缺乏复用性,所以也不常用,如果某个文件需要特殊配置,可以采用此方式。
/* eslint-env browser, node */     // 设置环境
/* global var1, var2:writable */   // 设置全局变量
/* eslint eqeqeq: "off", curly: "error" */    // 设置规则
  • 配置文件(推荐):提供.eslintrc.*文件或者在package.jsoneslintConfig属性中配置。

提示:由于使用配置文件简单直观,所以是我最常用的方式,下面的内容也基于此方式,其他方式也大同小异,唯格式有所差异。

上面的.eslintrc.中的是指ESLint的配置文件支持多种文件格式:jscjsyamlymljson,如果在当前目录同时存在多个格式的配置文件,ESLint仅会选择其中一个,优先选择的顺序如下:

  1. .eslintrc.js(推荐,eslint --init生成的默认就是此格式的配置)
  2. .eslintrc.cjs
  3. .eslintrc.yaml
  4. .eslintrc.yml
  5. .eslintrc.json
  6. .eslintrc(废弃)
  7. package.json

由于.eslintrc.js配置比较灵活且具有较高的优先级,所以一般我们都适用此格式的配置文件。

配置组合及优先级

当使用.eslintrc.*package.json方式进行配置时,会触发级联组合行为。它的工作方式是:

  • 优先使用就近的.eslintrc.*配置,然后在所有父级目录依次查找所有配置,以此类推,直到根目录或找到某个配置了"root":true的配置文件,才会停止继续向上级查找。
  • 上一步匹配到的所有配置将会按照查找到的顺序(由内而外)进行组合,内层的配置拥有更高的优先级,如果组合后配置项有冲突,将采用高优先级的配置项(内>外)。
  • 如果在同一目录中同时有.eslintrc.*package.json文件,将使用前者的配置,后者的配置将会忽略。
  • 可以在配置中添加"root":true将该目录强制设置为根目录,来阻止继续查找。

举个:chestnut::

your-project
├── package.json  <- { "eslintConfig": {...} }
├── .eslintrc.js
├── lib
  └── source.js
└─┬ test1
  ├── .eslintrc.js
  └── index.js
└─┬ test2
  ├── .eslintrc.js  <- { "root": true }
  └── index.js

如上的目录结构,大概有以下几种组合方式:

目标 生效配置 组合方式
/lib/* /.eslintrc.js lib目录无配置文件,会向上级查找,找到/.eslintrc.js/package.json,但是它们在同一目录,仅/.eslintrc.js生效。
/test1/* /test1/.eslintrc.js+/.eslintrc.js test1目录找到配置后,继续向上查找,找到/.eslintrc.js/package.json(忽略),将/test1/.eslintrc.js/.eslintrc.js组合
/test2/* /test2/.eslintrc.js test2目录存在配置,且配置了"root":true,所以不会向上查找,仅/test2/.eslintrc.js生效

ESLint支持的配置方式比较多,有必要介绍一下他们的优先级,从高到低的顺序如下:

优先级 配置方式 描述
1 内联注释配置 /*eslint-disable*//*eslint-enable*/ /*global*/ /*eslint*/ /*eslint-env*/
2 命令行选项 --global --rule --env -c--config
3 项目级配置文件 .eslintrc.*package.json

了解这些组合规则及优先级很有必要,可以进行合理利用。

配置项

前面我们有提到,ESLint配置主要是针对解析器环境全局规则插件这几个内容,那么下面我们就来仔细看看。

提示:后面的配置均采用.eslintrc.js方式,如需其他方式请自行探索。

解析器

默认情况下,ESLint使用Espree作为其解析器,不过我们也可以指定其他解析器。

// .eslintrc.js
module.exports = {
	parser: "esprima"
}

下面是一些常用的解析器:

  • Esprima:ESLint早期采用的解析器,Espree最初就是在它基础上创建的。
  • @ babel/eslint-parser :使babel和ESLint兼容,对一些Babel语法提供支持。
  • @ typescript-eslint/parser:TSLint被弃用后,TypeScript提供了此解析器用于将其与ESTree兼容,使ESLint对TypeScript进行支持。

除了配置解析器,还可以提供一些选项对解析器进行配置:

// .eslintrc.js
module.exports = {
	"parser": "esprima",
	"parserOptions": {
        "ecmaVersion": 6, // 默认5,指定ECMAScript版本,支持年份和版本号两种格式,用于支持该版本新语法
        "sourceType": "module", // 默认'script',使用了ESModule需要设置为'module',否则import、export关键字会报错
        "ecmaFeatures": {
            "jsx": true,   // 启用jsx语法
            "globalReturn": false,  // 是否允许全局return
            "impliedStrict": false  // 是否启用严格模式,仅ecmaVersion大于5有效
        }
    }
}

环境

环境配置主要用于预定义一些全局环境变量及相应环境的语法支持,可以指定一个或者多个环境。

// .eslintrc.js
module.exports = {
    "env": {
        "browser": true,
        "node": true
    }
}

常用的环境如下:

环境 描述
browser 添加浏览器的全局变量,如window
node 添加Node.js全局变量和Node.js作用域
es6es2017es2020es2021... 添加该版本的全局变量,并将parserOptions.ecmaVersion设置为该版本号
amd 添加require()define()全局变量
jquery 添加jQuery$全局变量

更多环境请查看官方文档

一些插件中提供了环境,可以按照如下格式使用:

// .eslintrc.js
module.exports = {
    "plugins": ["example"],
    "env": {
        "example/custom": true
    }
}

全局变量

在使用一些全局变量,而这些变量又没在当前文件中定义时,ESLint会抛出错误,告诉我们该变量未定义,这时我们可以手动在配置文件中将该变量添加到全局变量。

// .eslintrc.js
module.exports = {
    "globals": {
        "var1": "writable",
        "var2": "readonly",
        "var3": "off"
    }
}

支持三种配置值:

  • writable:允许变量被修改覆盖
  • readonly:设置变量仅为只读,不可覆盖
  • off:设置变量禁止使用

插件

ESLint提供了插件机制,可以让开发者自定义校验逻辑、校验规则,或对一些特殊语法提供支持,插件可以对外提供其扩展配置、规则、环境等配置。ESLint的插件均以eslint-plugin-开头,在配置的时候需要省略该前缀。

// .eslintrc.js
module.exports = {
    // ...
    "plugins": [
        "jquery",   // eslint-plugin-jquery
        "@foo/foo", // @foo/eslint-plugin-foo
        "@bar"      // @bar/eslint-plugin
    ],
    "extends": [
        // 扩展插件中的配置,需要加上plugin:
        "plugin:@foo/foo/recommended",
        "plugin:@bar/recommended"
    ],
    "rules": {
        // 修改插件中的规则
        "jquery/a-rule": "error",
        "@foo/foo/some-rule": "error",
        "@bar/another-rule": "error"
    },
    "env": {
        // 修改插件中的环境
        "jquery/jquery": true,
        "@foo/foo/env-foo": true,
        "@bar/env-bar": true,
    }
    // ...
}

一些常用的插件:

插件 描述
eslint-plugin-react 对react提供支持
eslint-plugin-vue 对vue提供支持,支持.vue文件
eslint-plugin-prettier prettier支持按ESLint规则格式化
@typescript-eslint/eslint-plugin 提供对TypeScript的支持

提示:如果想自己开发插件,可以基于ESLint官方提供的模板generator-eslint开发。

规则

ESLint提供了大量的规则 ,我们可以针对这些规则进行精细的的控制。

配置的格式如下:

// .eslintrc.js
module.exports = {
    "rules": {
        "eqeqeq": "off",
        "curly": "error",
        "quotes": ["error", "double"]
    }
}

上面的配置值也可以采用数值的形式,对应关系如下:

配置值 描述
off0 关闭对该规则的检测
warn1 启用对改规则的检测,不满足时抛出警告
error2 启用对改规则的检测,不满足时抛出错误

配置的规则如果有配置项,可以把值写成数组格式,第一个元素为配置的值,第二个元素为配置项。

扩展配置

ESLint提供了如此多的规则,我们不可能每次都从头一个一个去配置吧!所以ESLint提供了extends配置项,我们可以基于一些成熟的配置来做扩展,也可以覆写其规则:

// .eslintrc.js
module.exports = {
    "plugins": [
        "react"
    ],
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended" // 扩展插件中的配置
    ],
    "rules": {
       "react/no-set-state": "off"  // 覆写规则
    }
}

目前社区提供了很多配置集供我们扩展,这里列举一些常用的:

配置 描述
eslint:recommended ESLint内置,开启了一些推荐的核心校验规则
eslint:all ESLint内置,开启了所有的核心校验规则
eslint-config-airbnb 按照airbnb风格规则进行校验
eslint-config-standard 按照standard风格规则进行校验
eslint-config-prettier 关闭prettier有冲突的规则

除了使用社区提供的配置,团队也可以自己定制一套配置,然后发布到npm,以便团队共享配置。发布的包须以eslint-config-开头来进行命名,如eslint-config-myconfig,并建议将关键字设为eslintconfig,以便其他人能够找到。包的内容和.eslintrc.js类似:

// eslint-config-myconfig/index.js
module.exports = {

    globals: {
        MyGlobal: true
    },

    rules: {
        semi: [2, "always"]
    }

};

禁用和忽略

ESLint虽好,但是总有些情况我们还是想静静,不愿被这太多的“俗世凡尘”规则所羁绊。尤其是拿到一份上古时代的代码,开启ESLint校验后,可能会让你怀疑你的出现可能是个错误:broken_heart::broken_heart::broken_heart:,这时禁用或忽略一些规则和文件就是个不错的主意了。

禁用规则有如下几种方式:

// 1. 放在文件最前面,对该文件检测时禁止所有规则
/* eslint-disable */
alert('foo');

// 2. 对该文件检测时禁止指定的规则
/* eslint-disable no-alert, no-console */
alert('foo');
console.log('bar');

// 3. 对该行检测时禁止所有规则
alert('foo'); // eslint-disable-line
alert('foo'); /* eslint-disable-line */

// 4. 对下一行行检测时禁止所有规则
// eslint-disable-next-line
alert('foo');
/* eslint-disable-next-line */
alert('foo');

// 5. 对该行检测时禁止指定规则
alert('foo'); // eslint-disable-line no-alert, quotes, semi
alert('foo'); /* eslint-disable-line no-alert, quotes, semi */

// 6. 对下一行行检测时禁止指定规则
// eslint-disable-next-line no-alert, quotes, semi
alert('foo');
/* eslint-disable-next-line no-alert, quotes, semi */
alert('foo');

除了上述在文件中配置的方式外,也可以通过配置来对一组文件禁用校验规则:

// .eslintrc.js
module.exports = {
  "rules": {...},
  "overrides": [
    {
      "files": ["*-test.js","*.spec.js"],
      "rules": {
        "no-unused-expressions": "off"
      }
    }
  ]
}

ESLint还提供了一个文件.eslintignore用来忽略对文件的校验,其中配置的目录均会被ESLint忽略。

/build/
/config/
/dist/
/*.js

一些案例

上面我们介绍了ESLint的使用方法,下面我们就来看一下一些常用的使用案例:

ESLint +TypeScript

要对TypeScript进行支持,需要配置对应的解析器@typescript-eslint/parser 来支持TS特殊的语法,另外还需要安装@typescript-eslint/eslint-plugin来提供校验规则。

  1. 安装依赖包
npm install @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint typescript --save-dev
  1. 配置解析器,更多的解析器配置查看[该文档 nginx.conf ](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser)
// .eslintrc.js
module.exports = {
  "parser": "@typescript-eslint/parser", // 配置解析器
  "parserOptions": {
      "ecmaFeatures": {
        "jsx": true  // 如果用到jsx需要开启
      },
      "project": "./tsconfig.json",  // ts配置文件
      // ...更多配置
  }
}
  1. 配置插件及规则配置
// .eslintrc.js
module.exports = {
  "parser": "@typescript-eslint/parser",
  "plugins": ["@typescript-eslint"], // 配置插件
  "extends": ["plugin:@typescript-eslint/recommended"] // 扩展继承typescript-eslint推荐的规则
  "rules": {
      "@typescript-eslint/indent": ["error", 2], // 覆写插件校验规则配置
  }
  // ...
}

更多typescript-eslint用法可以查看typescript-eslint文档

ESLint + Prettier

Prettier

在开始这部分内容前,有必要先简单了解一下Prettier

Prettier是一款“有主见”的代码格式化工具,它支持多种语法,如JSX、Vue(vetur中使用了Prettier)、TypeScript、Less、Sass、JSON、GraphQL等,基本上前端能用到的文件格式它都可以搞定。而且它能够在多种场景下使用,是当下最流行的格式化工具。

下面我们来看下最常用的一种方式,即作为编辑器插件来使用:

  1. 安装VSCode插件Prettier - Code formatter
ext install esbenp.prettier-vscode

image-20200925171718606
image-20200925171718606

  1. 安装Prettier
npm install -g prettier # 全局安装
npm install -D prettier # 推荐本地安装
  1. 在项目中添加配置,Prettier同样支持多种格式的配置文件,这里我们使用prettier.config.js
module.exports = {
  printWidth: 80, // 每行代码长度(默认80)
  tabWidth: 2, // 每个tab使用多少空格(默认2)
  useTabs: false, // 使用tab进行缩进(默认false)
  semi: true, // 结尾使用分号(默认true)
  singleQuote: false, // 使用单引号(默认false)
  trailingComma: 'none', // 使用尾逗号(默认none)
  bracketSpacing: true, // 对象大括号间使用空格(默认true)
  jsxBracketSameLine: false, // 多行JSX中的>放置在最后一行的结尾,而不放在新行(默认false)
  arrowParens: "avoid" // 箭头函数的参数只有一个时是否带括号(默认avoid)
};

提示:关于更多配置项请查看Prettier-Options

这样配置好以后,在VSCode执行格式化时,选择Prettier即可按照我们配置的格式进行格式化了。这样就避免了因为大家编辑器配置不一样而导致格式化后的代码风格不统一的问题。

那这货和ESLint有什么关系呢?他俩为什么会有一腿呢?

ESLint和Prettier的冲突

原来他们都会对代码的格式有操作,ESLint会检查并尽可能修复代码格式,Prettier按照配置格式化代码,而他们之间配置是不通用的,有些配置规则是有冲突的。所以就会出现用Prettier格式化后的代码,ESLint觉得是有问题的,而抛出错误提示。

而为了解决这个问题,就需要使用到eslint-plugin-prettiereslint-config-prettier:

  • `eslint-plugin-prettier:将Prettier的规则设置到ESLint的规则中。

  • eslint-config-prettier:关闭ESLint中与prettier中会发生冲突的规则。

npm install -D eslint-plugin-prettier eslint-config-prettier
// .eslintrc.js
module.exports = {
    extends: [
        'plugin:prettier/recommended' // 也可以配置extends:["prettier"],plugins: ["prettier"]
      	// 'prettier/@typescript-eslint' // 如果是TypeScript可以加上这个,解决@typescript-eslint和prettier的冲突
    ],
    rules: {
        "prettier/prettier": [  // 覆写、自定义prettier规则
          "error",
          {
            "singleQuote": true,
            "trailingComma": "none",
            "bracketSpacing": true,
            "jsxBracketSameLine": true
          }
        ]
    }
}

现在,ESLint和Prettier就可以幸福的在一起了:tada::tada::tada::tada:。

工程化

前面我们了解了ESLint和Prettier,这些工具可以很好的规范我们书写的代码,他们都只工作在我们开发的时候,而并不能保证大家提交到仓库的代码都是符合规范的。

比如,部门新来了一个小伙伴,觉得有这些条条框框的限制很麻烦,所以他禁用掉了这些工具,开发完成直接把代码提交到了仓库。所以我们需要做一些限制,不合规范的代码是禁止提交的,来提高库中代码的质量。

这里我们可以使用git hooks来做,借助 husky & lint-staged 来实现。

  • husky:可以很方便的在package.json里面定义git钩子
  • lint-staged:仅对git提交的代码(不是所有)使用一些Linter操作,
# 安装 husky  lint-staged
npm i -D lint-staged husky
// package.json
"lint-staged": {
  "**/**.{js,json,pcss,md,vue}": [
    "prettier --write", // 先执行格式化
    "eslint --fix",
    "git add"
  ]
},
"husky": {
  "hooks": {
    "pre-commit": "lint-staged"
  }
},

这样设置以后,在每次提交的时候就会进行代码检查,只有通过检查后才能进行提交。

提示:由于这些操作都是在本地,所以还是能通过一定手段跳过检查,有CI/CD的话可以在远端来做,防止跳过检查。

参考资料:eslint+husky+prettier+lint-staged提升前端应用质量如何制定企业级代码规范与静态检查

结语

到这里,ESLint就介绍完了,如果想更加深入了解ESLint可以查看ESLint 工作原理探讨

无论在写代码还是做其他事情,其实都应该用长远的眼光来看,刚刚使用的时候可能会有很多问题,改起来也很费时费力,但是只要坚持下去,代码质量和开发效率都会得到提升,前期的付出都是值得的。

这些工具并不是必须的,没有他们你同样可以可以完成功能开发,但是利用好这些工具,可以写出更高质量的代码。特别是一些刚刚接触的人,可能会觉得麻烦而放弃使用这些工具,失去了一次提升代码的好机会。

« 【前端工程化】篇七 沧海遗珠-其他工具 【转】你不一定要逆风翻盘,但请一定向阳而生 »