前端项目配置 ESLint/Prettier

1,918 阅读10分钟

前言

现在前端项目基本都采用 ESLint 和 Prettier 配合约束代码规范和代码自动化格式。

目的

  1. 团队中的所有开发人员用一套代码规范规则作为日常开发约束;
  2. 有一套自动化工具,来帮我们检测代码是否规范;如果不规范,则自动按照既定规范进行格式化。

工具

  1. ESLint:设置代码规范的规则,避免开发者使用方式的错误(负责代码质量检查,以及代码格式化);
  2. prettier:用于规范风格,格式化代码(只专注于代码格式化,不对代码做质量检查)。

一、ESLint

1、安装使用:

  • 安装:
// 安装时 Node 版本需高于 12
npm install eslint --save-dev
  • 生成配置文件:
./node_modules/.bin/eslint --init
  • 进行简单配置:
// .eslintrc.js
module.exports = {
  "env": { // 指定代码的运行环境
    "browser": true,
    "es6": true
  },
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": "latest", // 支持 ES 最新版本的语法校验
    "sourceType": "module" // 设置 ECMAScript modules
  },
  // rules: https://eslint.bootcss.com/docs/rules/
  "rules": {
    // 禁止出现定义了,但未使用过的变量
    "no-unused-vars": "warn",
    // 阻止 var 的使用,推荐用 let 和 const
    "no-var": "warn",
  }
};
  • 指定文件或目录运行 ESlint:
./node_modules/.bin/eslint src/index.js
  • 配置执行脚本:
    通常,为了简化操作,我们会将运行命令配置在 scripts 执行命令中。
// package.json
{
  "scripts": {
    "lint": "eslint src --ext .js,.jsx,.ts,.tsx",
    // 对代码自动修复(并非所有的错误和警告都能被自动修复,
    // 只会修复一些格式类问题。例如:声明变量但未使用,这无法修复)
    "lint-fix": "eslint src --ext .js,.jsx,.ts,.tsx --fix"
  }
}
  • VSCode 编辑器配置 ESLint: 在开发过程中,我们希望编辑器能够给出 ESLint 的规范校验提示,而不是执行 eslint 代码检查命令才去做检查,因此我们需要配置插件:
  1. 在 extensions 中搜索安装 ESLint 插件;
  2. 进入 Settings,可以配置保存代码自动根据 ESLint 规则进行代码修复:
{
  ...
  // 缩进字符数为 2 个
  "editor.tabSize": 2,
  // 每次保存时将代码按eslint格式进行保存(可选的)
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  // 配置编辑器支持对 TS 文件类型的 ESlint 校验(TS 环境需要支持)
  "eslint.validate": [
    "typescript",
    "typescriptreact"
  ],
}
  • 定义要被 ESLint 校验忽略的文件/目录:
    默认情况下,VSCode 编辑器会校验项目下的所有文件,可以定义 ignore 文件对指定目录(比如这里是 publish 目录)进行忽略。
// .eslintignore
publish
node_modules

注意:关于 .eslintignore 在 VSCode 编辑器下不生效情况:如果 eslintignore 配置文件,不在 VSCode 打开的工程跟目录下,可能造成不生效。

2、Parser 解析器:

ESLint 默认使用 Espree 作为解析器解析 JavaScript。通过配置 parserOptions 来设置 ECMAScript 版本以及 JSX。

// .eslintrc.js
{
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": "latest", // 支持 ES 最新版本的语法校验
    "sourceType": "module" // 设置 ECMAScript modules
  },
}

3、Environments 环境:

指定程序运行的环境,会根据设定的环境预定义相关全局变量。

{
  "env": {
    "browser": true, // 浏览器全局变量 
    "es6": true,
  },
}

4、Globals 全局变量:

程序所用到的自定义全局变量在这里定义,避免 ESLint 对它们的使用发出警告(只有在配置 "extends": "eslint:recommended" 时会启用 no-undef 发出警告)。

{
  "globals": {
    "i18n": "writable", // 可写
    "$": "readonly", // 只读
  },
}

5、Plugins 插件:

ESLint 支持插件规则的配置,比如配置 React 环境插件:

  • 安装:
npm install eslint-plugin-react --save-dev
  • 配置:
{
  "extends": [
    "plugin:react/recommended"
  ],
  "plugins": [
    "react"
  ],
  // 使用 eslint-plugin-react 插件时需要指定 React 版本
  "settings": {
    "react": {
      "version": "16" // or "detect"
    }
  },
}

6、Rules 规则:

ESlint 的自定义配置规则在 rules 下进行配置,每一个规则值必须是以下值之一:

  • 关闭:"off" 或者 0
  • 警告:"warn" 或者 1
  • 错误:"error" 或者 2

项目中推荐使用的规范规则如下:

{
  // rules: https://eslint.bootcss.com/docs/rules/
  "rules": {
    // 统一缩进(2个空格)
    "indent": ["error", 2, { "SwitchCase": 1 }],
    // "@typescript-eslint/indent": ["error", 2, { "SwitchCase": 1 }],
    // 运算符前后需要空格,如:let a = 12;
    "space-infix-ops": "error",
    // 对象 key 和 value 之间有空格,如:key: value
    "key-spacing": "error",
    // 强制在大括号中使用一致的空格,空{}除外。如:{ a: 1 } 符合,{ a: 1} 不符合
    "object-curly-spacing": ["error", "always"],
    // 逗号前后是否需要空格,如:let arr = [1, 2, 3];
    "comma-spacing": "error",
    // 强制所有控制语句使用一致的括号风格,影响 if,for,while 等的花括号风格;这里允许写在一行,要换行必须有花括号
    "curly": ["error", "multi-line"],
    // 强制在关键字前后使用一致的空格,如:if / else 关键字空格保持一致
    "keyword-spacing": "error",
    // 禁止在条件语句中出现赋值操作符,如:if (user.jobTitle = "manager") 
    "no-cond-assign": ["error", "except-parens"],
    // 禁止对象字面量中出现重复的 key
    "no-dupe-keys": "error",
    // 禁止出现重复的 case 标签
    "no-duplicate-case": "error",
    // 要求使用 === 和 !==,禁用(== 和 !=)
    "eqeqeq": "error",
    // 禁止出现多个空格。如:if (key   !== key2) {}
    "no-multi-spaces": "error",
    // 禁止重新声明变量。如:var a = 3;、var a = 10;
    "no-redeclare": "error",
    // 强制在 JSX 属性中使用一致的双引号。如:<div className="box">Box</div>
    "jsx-quotes": ["error", "prefer-double"],
    // 要求箭头函数的箭头之前或之后有空格。如:const fn = () => {}
    "arrow-spacing": "error",
    // ESModule 禁止重复导入。
    "no-duplicate-imports": "error",
    // JSX 元素上不能定义重复的 Prop
    "react/jsx-no-duplicate-props": "error",
    // 在一组数组中元素必须定义 key 属性
    "react/jsx-key": "error",
    // 禁止出现定义了,但未使用过的变量
    "no-unused-vars": "warn",
    // 禁用不必要分号(重复使用多个)
    "no-extra-semi": "warn",
    // 阻止 var 的使用,推荐用 let 和 const
    "no-var": "warn",
    // 防止在 React 组件定义中丢失 props 类型定义
    "react/prop-types": "off",
    // 禁止不使用 setState 的方式去更新 state,而是直接去赋值 state
    "react/no-direct-mutation-state": "off",
    // 禁止使用 string 类型的 ref 绑定 DOM 元素实例
    "react/no-string-refs": "off",
  }
}

7、配置 TS 语法校验:

  • 安装:
npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser -D
  • 配置:
{
  ...
  "parser": "@typescript-eslint/parser", // 配置ts解析器
  "plugins": ["@typescript-eslint"],
}
  • 注意:
    通常我们会在 rules 中配置 "no-unused-vars": "warn" - 定义了但没有使用的变量进行警告;

但在 TS 环境下,ES enum 枚举类型属性也会收到影响,为此这里需要进行配置,使用 TS 特有的 "no-unused-vars" 规则:

"rules": {
  // 禁止出现定义了,但未使用过的变量
  "no-unused-vars": "off", // 禁用 ESLint 默认的规则
  "@typescript-eslint/no-unused-vars": ["warn"], // 启用 TS 规则
}

8、配置 Webpack 打包语法校验:

在使用 Webpack 启动本地服务,或者是进行打包时,也可以在这个过程进行 ESLint 代码校验。

  • 安装:
npm install eslint-webpack-plugin -D
  • 配置:
// webpack.config.js
const ESLintPlugin = require('eslint-webpack-plugin'); // ESlint 代码检查
module.exports = {
  ...
  plugins: [
    ...
    // 在打包编译时进行代码验证并将结果输出到控制台
    new ESLintPlugin({
      context: 'src',
      extensions: ['.ts', '.tsx', '.js', '.jsx']
    }),
  ]
}

9、Git 代码提交时进行代码检测:

  • 手动执行 npm run lint 命令进行代码校验,没有问题再进行提交;
  • 另一种可以配置 hook 在代码提交时进行检测拦截。

下面我们借助 pre-commit 来实现 Git 提交检测拦截。

  • 安装:
npm install pre-commit -D
  • 配置:
{
  "scripts": {
    "lint": "eslint src --ext .js,.jsx,.ts,.tsx",
    "lint-fix": "eslint src --ext .js,.jsx,.ts,.tsx --fix"
  },
  "pre-commit": [
    "lint"
  ],
}

在执行 git commit 命令时会调用 lint 命令去检测代码,如果校验存在 error 警告,则会终止 commit 的提交,校验的警告信息允许 commit 提交。

10、忽略代码校验:

上面我们使用 .eslintignore 来忽略指定的目录或文件跳过 ESLint 的工作。

如果想在某一个文件中对部分代码的校验进行忽略,可以通过以下几种方式:

  1. 关闭整个文件代码的 ESLint 校验: 在文件最上方添加:
/* eslint-disable */
... code
  1. 关闭文件中某一段落代码的 ESLint 校验:
/* eslint-disable */
code
/* eslint-enable */
...code
  1. 关闭当前行校验:
code // eslint-disable-line
  1. 关闭下一行校验:
// eslint-disable-next-line
code

二、Prettier

Prettier 作用是对代码格式的校验和统一格式化,不会对代码质量进行校验

代码格式问题通常指的是:单行代码展示长度、tab缩进空格长度、空格、单引号/双引号的统一使用。

代码质量问题指的是:未使用变量、三等号、全局变量声明等问题。

在 ESLint 推出 --fix 命令行参数之前,ESLint 并没有自动化格式代码的功能,要对一些格式问题做批量格式化只能用 Prettier 这样的工具。

而在 ESLint 推出 --fix 命令行参数之后会对代码做一定的格式化,如果你觉得 ESLint 提供的格式化代码够用了,也可以不使用 Prettier。

下面我们来看看 ESLint 结合 Prettier 一起使用。

1、安装 Prettier:

npm install --save-dev --save-exact prettier // --save-exact 精确版本安装
yarn add --dev --exact prettier

2、创建配置文件:

  • 在项目根目录创建 .prettierrc 文件用作填入配置;
  • 在项目根目录下创建 .prettierignore 忽略对某些文件或目录进行格式化。

一旦结合编辑器开启后,会对项目内所有文件使用 Prettier 进行格式化。如项目中引入的 *.min.js 不希望被格式化而增大文件体积,可以在 .prettierignore 进行配置,其他类型文件同理。

// .prettierignore
*.md
*.min.js
...

尝试使用 .prettierrc.js、prettier.config.js 作为配置文件,在 VSCode 中结合使用时并未生效,这里使用 .prettierrc json 形式编写配置文件。

3、常用配置:

// 配置参考:https://www.prettier.cn/docs/options.html

{
  // 指定一行所承载的字符长度,当超过设定值时,自动进行格式化换行排列
  // (场景:函数参数过多过长、元素属性在一行内编写过多过长)
  printWidth: 150,

  // 代码缩进使用的空格数
  tabWidth: 2,

  // 元素的右括号显示在最后一行的末尾(比如 HTML 元素的 ">" 不会换行单独展示在一行)
  bracketSameLine: true,

  // 在代码结尾处打上分号 ;
  semi: true,

  // 对字符串统一使用单引号
  singleQuote: false,

  // 在 JSX 中统一使用单引号
  jsxSingleQuote: false,

  // 在箭头函数只有一个参数时,在参数周围添加括号 (x) => x
  arrowParens: "always",

  // 在 HTML、Vue、JSX 中执行每行单个属性
  singleAttributePerLine: false,

  // 对象括号和属性之间使用空格
  bracketSpacing: true,
}

4、集成在编辑器:

借助 Code Editor 编辑器保存时自动进行格式化处理。这里以 VSCode 为例:

  • 在 vscode 编辑器扩展插件中搜索 prettier-vscode,选择 Prettier - Code formatter 进行安装并启用;
  • 打开 vscode settings.json 添加配置(更多配置参考 Prettier - Code formatter 插件介绍):
{
  "editor.defaultFormatter": "esbenp.prettier-vscode", // 所有文件均使用 Prettier 格式化
  "editor.formatOnSave": true // 保存时自动进行格式化处理
}

现在,对文件进行保存时,会自动读取 Prettier 配置进行格式化处理。

5、兼容 ESLint:

prettier 和 ESLint 经常会冲突,比如 rule indent,特别是在 React JSX 三目运算符中使用 ReactDOM.createPortal()

这种情况只能选择放弃其一。放弃的方式可以是:放弃全局配置使用忽略代码格式化

对于放弃全局配置,

  • 如果使用 Prettier,则关掉 ESLint indent rules;
  • 如果不使用 Prettier,则推荐开启 ESLint indent rules。

对于使用忽略代码格式化

  • 要么采用 ESLint rule,使用 Prettier 忽略代码格式;
  • 要么采用 Prettier 格式,使用 ESLint 忽略代码格式(上述示例 rule indent 冲突,可以考虑使用这种方式);

6、忽略代码格式化

官方文档:www.prettier.cn/docs/ignore…

忽略下一行代码的 Prettier 格式化,在代码上方添加:

# JS 文件的忽略使用方式
// prettier-ignore

# JSX 文件的忽略使用方式
{/* prettier-ignore */}

# HTML 文件的忽略使用方式
<!-- prettier-ignore -->

# CSS 文件的忽略使用方式
/* prettier-ignore */

# 更多文件的忽略编写方式参考:https://www.prettier.cn/docs/ignore.html

最后

如果团队成员代码编写格式规范自我约束较高,完全可以不用 Prettier 仅用 Eslint;反之推荐开启 Prettier。