前端 2020-12-09 20:47:03

在开发过程中,我们可以通过eslint、stylelint以及prettier来规范代码,保证代码的一致性和避免错误

Demo源码

https://github.com/m-alfred/webpack5

.eslintrc.js最终版配置

https://github.com/m-alfred/webpack5/blob/master/.eslintrc.js

eslint

安装

npm install eslint --save-dev

配置

我们可以通过.eslintrc.* 和 package.json 文件进行eslint规则配置。ESLint 将自动在要检测的文件目录里寻找它们,紧接着是父级目录,一直到文件系统的根目录(除非指定 root: true)。通过这个设定,我们可以对一个项目的不同目录配置不同规则。

ESLint 支持的文件格式和优先级:

  1. .eslintrc.js
  2. .eslintrc.yaml
  3. .eslintrc.yml
  4. .eslintrc.json
  5. .eslintrc - 弃用
  6. package.json - 配置eslintConfig属性

默认配置

{
    "extends": "eslint:recommended"
}

使用该配置将默认开启所有在规则页面被标记为 “√” 的规则。

另外,你可以在 npmjs.com 搜索 “eslint-config” 使用别人创建好的配置。

目前使用较多的是eslint-config-airbnb

只有在你的配置文件中扩展了一个共享的配置或者明确开启一个规则,ESLint 才会去校验你的代码。

parserOptions

解析器选项可以在 .eslintrc.* 文件使用 parserOptions 属性设置。可用的选项有:

  • ecmaVersion - 可以设置为 3、5(默认)、6、7、8、9 或 10 来指定你想要使用的 ECMAScript 版本。你也可以用使用年份命名的版本号指定为 2015(同 6),2016(同 7),或 2017(同 8)或 2018(同 9)或 2019 (same as 10)
  • sourceType - 设置为 "script" (默认) 或 "module"(如果你的代码是 ECMAScript 模块)。
  • ecmaFeatures - 这是个对象,表示你想使用的额外的语言特性:
    • globalReturn - 允许在全局作用域下使用 return 语句
    • impliedStrict - 启用全局 strict mode (如果 ecmaVersion 是 5 或更高)
    • jsx - 启用 JSX
    • experimentalObjectRestSpread - 启用实验性的 object rest/spread properties 支持。(重要:这是一个实验性的功能,在未来可能会有明显改变。 建议你写的规则 不要 依赖该功能,除非当它发生改变时你愿意承担维护成本。)

请注意,支持 ES6 语法并不意味着同时支持新的 ES6 全局变量或类型(比如 Set 等新类型)。对于 ES6 语法,使用 { "parserOptions": { "ecmaVersion": 6 } };对于新的 ES6 全局变量,使用 { "env":{ "es6": true } }. { "env": { "es6": true } } 自动启用es6语法,但 { "parserOptions": { "ecmaVersion": 6 } } 不自动启用es6全局变量。

Parser

.eslintrc 文件 parser 选项

ESLint 默认使用Espree作为其解析器,你可以在配置文件中指定一个不同的解析器,只要该解析器符合下列要求:

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

以下解析器与 ESLint 兼容:

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

env

一个环境定义了一组预定义的全局变量。 我们可以通过增加以下配置,引入node和browser环境的全局变量

env: {
    // 浏览器环境中的全局变量。
    browser: true,
    // Node.js 全局变量和 Node.js 作用域。
    node: 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 一样的全局变量。
  • mocha - 添加所有的 Mocha 测试全局变量。
  • jasmine - 添加所有的 Jasmine 版本 1.3 和 2.0 的测试全局变量。
  • jest - Jest 全局变量。
  • phantomjs - PhantomJS 全局变量。
  • protractor - Protractor 全局变量。
  • qunit - QUnit 全局变量。
  • jquery - jQuery 全局变量。
  • prototypejs - Prototype.js 全局变量。
  • shelljs - ShellJS 全局变量。
  • meteor - Meteor 全局变量。
  • mongo - MongoDB 全局变量。
  • applescript - AppleScript 全局变量。
  • nashorn - Java 8 Nashorn 全局变量。
  • serviceworker - Service Worker 全局变量。
  • atomtest - Atom 测试全局变量。
  • embertest - Ember 测试全局变量。
  • webextensions - WebExtensions 全局变量。
  • greasemonkey - GreaseMonkey 全局变量。

globals

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

对于每个全局变量键配置,可以配置以下值:

  • writable: 允许重写变量
  • readonly: 不允许重写变量
  • off: 禁用全局变量
  • false: 同readonly
  • readable:同readonly
  • true:同writable
  • writeable:同writable
 globals: {
    window: true,
    document: true,
    XMLHttpRequest: true,
    fetch: true,
    // 允许重新赋值
    var1: 'writable',
    // 不允许重新赋值
    var2: 'readonly',
    // 表示var3不可用作全局变量
    var3: 'off'
  },
};

plugins

ESLint 支持使用第三方插件。在使用插件之前,你必须使用 npm 安装它。在配置文件里配置插件时,可以使用 plugins 关键字来存放插件名字的列表。插件名称可以省略 eslint-plugin- 前缀。

// 引入eslint-plugin-react插件
plugins: ['react'],

rules

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

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

这三个错误级别可以允许你细粒度的控制 ESLint 是如何应用规则(更多关于配置选项和细节的问题,请查看配置文件

规则值也可以是数组,数组第一个值表示错误级别

rules: {
    // eslint-config-airbnb默认警告console
    // 我们可以设置off将其关闭
    'no-console': 'off',
    "semi": ["error", "always"],
    "quotes": ["error", "double"]
}

注意:当指定来自插件的规则时,确保删除 eslint-plugin- 前缀。ESLint 在内部只使用没有前缀的名称去定位规则。

rules: {
    // 不要使用eslint-plugin-react/prop-types做id,必须省略前缀
    'react/prop-types': 'off',
}

overrides/files

若要禁用一组文件的配置文件中的规则,请使用 overrides 和 files。例如:

overrides: [
    {
      // 覆盖上面定义的规则,针对测试用例文件不做eslint校验
      files: ['*.test.js'],
      rules: {
        'no-unused-vars': 'off',
      },
    },
],

上面配置将通过.test.js文件中未定义变量的eslint校验

root

ESLint 一旦发现配置文件中有 "root": true,它就会停止在父级目录中寻找eslint配置。

{
    root: true
}

extends

一个配置文件可以被基础配置中的已启用的规则继承。

extends 属性值可以是:

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

ESLint递归地扩展配置,因此基本配置也可以具有 extends 属性。extends 属性中的相对路径和可共享配置名从配置文件中出现的位置解析。

rules 属性的覆盖规则:

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

忽略文件和目录

.eslintignore

在项目根目录创建一个.eslintignore,可以告诉 ESLint 去忽略特定的文件和目录。

.eslintignore 文件是一个纯文本文件,其中的每一行都是一个 glob 模式表明哪些路径应该忽略检测。例如,以下将忽略所有的 JavaScript 文件:

**/*.js

Globs 匹配使用 node-ignore,所以大量可用的特性有:

  • 以 # 开头的行被当作注释,不影响忽略模式。
  • 路径是相对于 .eslintignore 的位置或当前工作目录。
  • 忽略模式同 .gitignore 规范
  • 以 ! 开头的行是否定模式,它将会重新包含一个之前被忽略的模式。

除了 .eslintignore 文件中的模式,ESLint总是忽略 /node_modules/*/bower_components/* 中的文件。

例如:把下面 .eslintignore 文件放到当前工作目录里,将忽略项目根目录下的 node_modules,bower_components 以及 build/ 目录下除了 build/index.js 的所有文件。

# /node_modules/* and /bower_components/* in the project root are ignored by default

# Ignore built files except build/index.js
build/*
!build/index.js

命令行

格式:

eslint [options] [file|dir|glob]*

--ext

这个选项允许你指定 ESLint 在指定的目录下查找 JavaScript 文件时要使用的文件扩展名。注意:默认情况下,它使用 .js 作为唯一性文件扩展名。如果要检测ts、tsx文件。需要显示指定--ext

eslint --fix --ext .js,.jsx,.tx,.tsx src/

上面命令将检测并自动修复src目录下所有.js,.jsx,.tx,.tsx文件

配合vscode

vscode扩展中搜索@id:dbaeumer.vscode-eslint,安装并启用。

vscode配置文件中新增,保存时自动修复eslint错误

//是否开启vscode的eslint
  "eslint.enable": true, 
  // 开启debug
  "eslint.debug": true,
  // 指定要检查的扩展名文件
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    "typescript",
    "typescriptreact",
    "vue",
    "html",
  ],
  // 保存时自动修复
  "editor.codeActionsOnSave": {
    "source.fixAll": true,
    // 有时候source.fixAll不起作用
    "source.fixAll.eslint": true,
  },
  "[javascript]": { 
    "editor.defaultFormatter": "dbaeumer.vscode-eslint" 
  },
  "[javascriptreact]": {
    "editor.defaultFormatter": "dbaeumer.vscode-eslint" 
  },
  "[typescript]": { 
    "editor.defaultFormatter": "dbaeumer.vscode-eslint" 
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "dbaeumer.vscode-eslint" 
  },
  "[vue]": {
    "editor.defaultFormatter": "dbaeumer.vscode-eslint"
  },

常用配置

针对ESLint extension version >= 2.x

  • eslint.enable: enable/disable ESLint. Is enabled by default.
  • eslint.debug: 开启debug模式,输出eslint debug信息。
  • eslint.probe: 一个数组,指定哪些扩展名的文件需要被激活和校验。默认["javascript", "javascriptreact", "typescript", "typescriptreact", "html", "vue"]
  • eslint.validate: 一个数组, 用于指定要对其实施验证的文件。默认值:["javascript", "javascriptreact"]
  • editor.codeActionsOnSave: 如果设置为true,那么所有来自插件的可自动修复的eslint错误将会在保存时被修复。你也可以选择性地开启或者禁用指定语言。
    要禁用codeActionsOnSave的HTML文件,可以使用以下设置:
    "[html]": {
        "editor.codeActionsOnSave": {
          "source.fixAll.eslint": false
        }
      }
    
  • eslint.format.enable (从2.0.0起): 使用Eslint作为那些被Eslint校验的文件的格式化程序 . 如果想要将Eslint作为默认,当启用时请确保禁用其他格式化程序。 添加以下配置是个不错的方法:
// for JavaScript
  "[javascript]": { 
    "editor.defaultFormatter": "dbaeumer.vscode-eslint" 
  },
  // For TypeScript 
  "[typescript]": { 
    "editor.defaultFormatter": "dbaeumer.vscode-eslint" 
  },

规范Typescript代码

安装依赖

yarn add --dev @typescript-eslint/parser @typescript-eslint/eslint-plugin

基础配置:

// .eslintrc.js
config.parser = '@typescript-eslint/parser'; // 定义ESLint的解析器
config.extends = ['plugin:@typescript-eslint/recommended']; // 定义文件继承的子规范
config.plugins = ['@typescript-eslint']; // 定义了该eslint文件所依赖的插件

在ts项目中必须执行解析器为@typescript-eslint/parser,才能正确的检测和规范TS代码

ParserOptions

interface ParserOptions {
  ecmaFeatures?: {
    jsx?: boolean;
    globalReturn?: boolean;
  };
  ecmaVersion?: number;

  jsxPragma?: string;
  jsxFragmentName?: string | null;
  lib?: string[];

  project?: string | string[];
  projectFolderIgnoreList?: string[];
  tsconfigRootDir?: string;
  extraFileExtensions?: string[];
  warnOnUnsupportedTypeScriptVersion?: boolean;
}
  • ecmaFeatures
    • jsx - 默认否,是否开启JSX解析。
    • globalReturn - 允许在全局作用域下使用 return 语句
  • ecmaVersion - 默认2018,指定想要用的ECMAScript语法版本,可以接受以下版本号: es3, es5, es6, es7, es8, es9, es10, es11, ..., or es2015, es2016, es2017, es2018, es2019, es2020, ...
  • jsxPragma - 默认'React',用于创建JSX元素的标识符(在置换之后)。如果您使用的库不是React(如preact),那么您应该更改这个值。如果提供了parserOptions.project则不需要设置它。
  • jsxFragmentName - 默认null,用于JSX Fragment元素的标识符(在置换之后)。如果提供了parserOptions.project则不需要设置它。
  • lib - 默认['es2018'], 有关有效选项,请参见TypeScript编译器选项。指定可用的Typescript库。如果提供了parserOptions.project则不需要设置它。
  • project - 默认undefined,此选项使您可以提供项目tsconfig.json的路径。如果未设置tsconfigRootDir,相对路径即相对当前工作目录。如果打算从项目根目录以外的目录运行ESLint,则应考虑使用tsconfigRootDir。
  • 其他配置项见https://www.npmjs.com/package/@typescript-eslint/parser

prettier

prettier中文的意思是漂亮的、美丽的,它是一个代码格式化工具,可以帮助我们统一代码风格,保证代码的可读性

安装

yarn add --dev prettier

CLI

使用prettier命令运行prettier:

prettier [options] [file/dir/glob ...]
  • --write 格式化文件
  • --check 检查文件是否已运行过Prettier
    $ prettier --check prettier.lab.js
    Checking formatting...
    [warn] prettier.lab.js
    [warn] Code style issues found in the above file(s). Forgot to run Prettier?
    error Command failed with exit code 1.
    

配置

支持以下方式配置prettier规则

  • package.json中增加prettier属性
  • .prettierrc文件
  • .prettierrc.json, .prettierrc.yml, .prettierrc.yaml, 或 .prettierrc.json5 文件.
  • .prettierrc.js, .prettierrc.cjs, prettier.config.js, 或 prettier.config.cjs 文件通过module.exports导出配置对象
  • .prettierrc.toml文件

JS:

// prettier.config.js or .prettierrc.js
module.exports = {
  trailingComma: "es5",
  tabWidth: 4,
  semi: false,
  singleQuote: true,
};

详细配置项

https://prettier.io/docs/en/options.html

忽略文件和目录

要忽略指定文件或者目录可以使用.prettierignore。 语法同.eslintignore

# Ignore artifacts:
build
coverage

# Ignore all HTML files:
*.html

或者通过js注释,忽略指定代码片段

// prettier-ignore
matrix(
  1, 0, 0,
  0, 1, 0,
  0, 0, 1
)

结合eslint

eslint-plugin-prettier插件将Prettier作为ESLint规则运行,并将差异报告为单个ESLint问题。

安装eslint插件

yarn add --dev eslint-plugin-prettier

然后在eslint配置中添加:

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

推荐配置

如果禁用所有其他与代码格式有关的ESLint规则,并且仅启用检测潜在错误的规则,则此插件运行效果最好。 (如果另一个激活的ESLint规则在如何格式化代码方面与prettier的表现不一致,那么就不可能避免出现lint错误。)我们可以使用eslint-config-prettier禁用所有与格式化相关的ESLint规则。

通过plugin:prettier/recommended可一次性设置该插件和eslint-config-prettier。

  1. 安装eslint-config-prettier
    yarn add --dev eslint-config-prettier
    
  2. plugin:prettier/recommended作为最后一个扩展添加到eslint配置文件中
    {
      "extends": ["plugin:prettier/recommended"]
    }
    
  3. 其他的插件(如eslint-plugin-react)也会包含一些与prettier冲突的规则,可以配置如下为插件增加额外的排除项:
    {
      "extends": [
        "plugin:prettier/recommended",
        "prettier/flowtype",
        "prettier/react"
      ]
    }   
    

plugin:prettier/recommended展开后,实际上就是以下配置:

{
  "extends": ["prettier"],
  "plugins": ["prettier"],
  "rules": {
    "prettier/prettier": "error",
    // fix arrow-body-style and prefer-arrow-callback issue
    "arrow-body-style": "off",
    "prefer-arrow-callback": "off"
  }
}

prettier.config.js:

// 规范项目代码书写
module.exports = {
  // 使用单引号
  singleQuote: true,
  // 结尾分号
  semi: true,
  // Specify the number of spaces per indentation-level.
  tabWidth: 2,
  // Print trailing commas wherever possible when multi-line. (A single-line array, for example, never gets trailing commas.)
  trailingComma: 'es5',
  // Specify the line length that the printer will wrap on.
  // printWidth: 100,
  // Use single quotes instead of double quotes in JSX.
  jsxSingleQuote: true,
  // Print spaces between brackets in object literals.
  bracketSpacing: true,
  // Include parentheses around a sole arrow function parameter.
  /**
   * Valid options:
      "avoid" - Omit parens when possible. Example: x => x
      "always" - Always include parens. Example: (x) => x
   */
  arrowParens: 'always',
  // Format only a segment of a file.
  rangeStart: 0,
  rangeEnd: Infinity,
  // Prettier can restrict itself to only format files that contain a special comment, called a pragma, at the top of the file. This is very useful when gradually transitioning large, unformatted codebases to prettier.
  requirePragma: false,
  // Prettier can insert a special @format marker at the top of files specifying that the file has been formatted with prettier. This works well when used in tandem with the --require-pragma option. If there is already a docblock at the top of the file then this option will add a newline to it with the @format marker.
  insertPragma: false,
  proseWrap: 'never',
  // Specify the global whitespace sensitivity for HTML files
  htmlWhitespaceSensitivity: 'css',
  // For historical reasons, there exist two commonly used flavors of line endings in text files. That is \n (or LF for Line Feed) and \r\n (or CRLF for Carriage Return + Line Feed).
  endOfLine: 'auto',
};

常见问题

1. eslint无效

配置规则语法错误导致eslint无法正常运行

2. Parsing error: "parserOptions.project" has been set for @typescript-eslint/parser.\nThe file does not match your project config: .eslintrc.js.\nThe file must be included in at least one of the projects provided.

parserOptions.project被提供时,当前文件未被包含在tsconfig.json的include中就会出现上述错误。 可以通过以下两种方法解决https://www.npmjs.com/package/@typescript-eslint/parser:

  • parserOptions.createDefaultProgram = true;
    此选项允许您请求在指定项目设置后,如果文件不包含在所提供的tsconfig.json文件定义的项目中,则允许文件。 使用此选项将导致巨大的性能成本。 主要包括此选项是为了实现向后兼容。
  • parserOptions.project被指定并且createDefaultProgram为false时,你必须只校验tsconfig.json文件中指定的哪些文件。如果你已存在的tsconfig配置不包含所有你想要校验的文件时,你可以创建一个独立的tsconfig.eslint.json,设置parserOptions.project为该文件,来移除报错的文件:
{
  // extend your base config so you don't have to redefine your compilerOptions
  "extends": "./tsconfig.json",
  "include": [
    "src/**/*.ts",
    "test/**/*.ts",
    "typings/**/*.ts",
    // etc

    // if you have a mixed JS/TS codebase, don't forget to include your JS files
    "src/**/*.js"
  ]
}

3. 'React' was used before it was defined

https://github.com/typescript-eslint/typescript-eslint/issues/2540

4. can't find module @typescript-eslint/eslint-plugin/dist/configs/eslint-recommended

运行eslint -v发现版本号和自己希望的不同,原因是包管理器自动安装了依赖中的eslint某个版本

解决:
当前项目package.json中指定eslint版本

规则字典

1. eslint

eslint rules

2. typescript-eslint

typescript-eslint rules

参考资料

  1. https://eslint.bootcss.com/docs/user-guide/getting-started
  2. https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint
  3. 在Typescript项目中,如何优雅的使用ESLint和Prettier
  4. https://www.npmjs.com/package/@typescript-eslint/eslint-plugin
  5. https://www.npmjs.com/package/@typescript-eslint/parser
  6. tsconfig.json
  7. 使用ESLint+Prettier来统一前端代码风格
  8. https://www.npmjs.com/package/eslint-plugin-prettier
  9. https://prettier.io