使用 ESLint、Prettier 和 Stylelint

前言

无论是多人协作还是个人项目,代码规范都非常重要。遵循代码规范不仅能减少基本语法错误,同时也保证了代码的可读性。而代码风格检查则是确保代码规范一致性的重要工具之一。

ESLint

ESLint 是什么?

ESLint 是一个用于检查和修复 JavaScript 代码中问题的代码检测工具。它能够帮助你发现并修复 JavaScript 代码中的问题。

ESLint 的作用包括:

  • 语言语法检查:比如检查出字符串引号不匹配或函数调用括号缺失的问题
  • 编码错误检查:比如检查出在代码中使用了一个不存在的变量,或者定义了一个变量却没有使用的问题
  • 代码风格检查:比如检查出开发者没有使用分号的问题

安装 ESLint

使用 Vue Cli 安装

vue add eslint
# or
vue add @vue/cli-plugin-eslint

在输入完命令后,需要回答一些问题来根据你的项目需求和个人偏好进行配置。问题如下:

  • Pick an ESLint config(选择一个 ESLint 配置预设)

    • Error prevention only(只检测错误)
    • Airbnb(安彼迎)
    • Standard(标准)
    • Prettier(Prettier)
  • Pick additional lint features(选择什么时候进行代码检查)

    • Lint on save(保存时检查)
    • Lint and fix on commit(提交代码时检查)

在回答完问题后,vue-cli 会自动创建一个 ESLint 配置文件 .eslintrc.js,并自动安装以下依赖:

  • eslint:ESLint 核心模块
  • eslint-plugin-vue:ESLint 插件,该插件用于提供针对 Vue.js 代码的规则和检查
  • prettier:Prettier 核心模块
  • eslint-plugin-prettier:ESLint 插件,该插件用于将 Prettier 的格式化规则集成到 ESLint 中
  • @vue/eslint-config-prettier:ESLint 插件,它将禁用与 Prettier 格式化规则冲突的 ESLint 规则

ESLint 常用配置项

  • root:定义根配置
  • env:定义运行环境
  • rules:定义检查规则
  • plugins:规则拓展
  • extends:集成配置方案
  • parser:语法解析器配置

下面是每个配置项的详细介绍:

root

默认情况下,ESLint 会在所有父级目录中寻找配置文件,一直到根目录。这样可以让所有项目都遵循同一套规则。你也可以将 .eslintrc.js 配置文件中的 root 设置为 true,这样 ESLint 一旦发现配置文件中有 root: true,它就会停止在父级目录中寻找。

env

这个选项用于定义项目代码运行的环境,每个环境都包含一组特定的预定义全局变量:

  • browser — 浏览器全局变量
  • node — Node.js 全局变量和 Node.js 作用域
  • es6 — 启用除模块之外的所有 ES6 功能

...

比如项目要启用浏览器环境和 Node.js 环境:

module.exports = {
  // ...
  env: {
    browser: true,
    node: true,
  },
};

rules

规则的值有两种格式:数组和字符串/数字。如果是数组,则可以设置两个内容:

第一项内容定义规则是关闭还是打开:

  • off0:关闭规则,ESLint 不对该规则进行检查
  • warn1:将规则作为警告打开(不影响退出代码)。在开发环境下,终端会输出警告信息,但不会影响功能页面的展示
  • error2:将规则作为错误打开(触发时退出代码为 1)。在开发环境下,终端输出错误信息,浏览器页面也会显示错误信息而不是正常的功能展示

第二项内容是为该规则提供的参数。

如果规则的值是字符串/数字,则只定义规则的关闭或打开。

以下是禁用 JavaScript 中的 console 对象的方法调用的示例,对应的 ESLint 规则名称是 no-console

module.exports = {
  // ...
  rules: {
    // 表示在代码中不允许直接调用 console.log/error/warn 等方法,否则将报错
    "no-console""error",

    // 表示在代码中不推荐直接调用 console.log/error/warn 等方法,否则将发出警告
    "no-console"1,

    // 表示在代码中可以直接调用 console.log/error/warn 等方法,因为规则被关闭了
    "no-console""off",

    // 表示在代码中不允许直接调用 console.log 方法,但允许使用 warn 和 error 方法,否则将报错
    "no-console": ["error", { allow: ["warn""error"] }],
  },
};

plugins

插件(plugins)是用于扩展 ESLint 内置规则的。ESLint 主要用于对 JavaScript 代码进行语法检查,无法直接检查其他格式的文件内容。如果需要对这些文件内容进行检查,就需要使用插件配置(plugins)来扩展 ESLint 规则。例如:

  • eslint-plugin-vue:可以对 Vue 文件的 <template><script> 内容进行检查,具体使用方法请参考文档
module.exports = {
  // ...
  plugins: ["eslint-plugin-vue"],
  rules: {
    // ... eslint-plugin-vue 的 lint 规则
  },
};

需要注意的是,添加的插件(plugins)中的规则默认是未启用的,我们需要在规则(rules)中选择要使用的规则。也就是说,插件(plugins)需要与规则(rules)结合使用。

extends

可以看到,手动配置规则(rules)的工作量很大。这时 extends 发挥了作用。extends 可以理解为一个预设的插件(plugins)和规则(rules)的集合。

举例来说:eslint-plugin-vue 提供了一个名为 plugin:vue/recommended 的规则包。在 extends 中引用这个规则包相当于启用了一系列的规则:

module.exports = {
  // ...
  extends: ["plugin:vue/recommended"],
  rules: {
    // 此处无需手动一项一项配置 lint 规则,因为插件已经根据 recommended 选项自动设置了预设的规则包
  },
};

parser

ESLint 默认使用 Espree 作为其解析器,它仅支持 ES5 语法,不支持实验性语法和非标准语法(如 TypeScript 类型)。但是我们可以配置解析器(parser)以使 ESLint 支持其他语法。例如:

  • babel-eslint:使 ESLint 兼容 ES6 语法
module.exports = {
  // ...
  parserOptions: {
    parser: "babel-eslint",
  },
};

ESLint 常用命令

检查文件

npx eslint [文件或目录路径]

修复文件

npx eslint --fix [文件或目录路径]

指定检查的文件扩展名

默认情况下,ESLint 会检查 .js 文件,若想检查其他扩展名的文件,可以使用 --ext 命令自定义要检查的文件类型。

# 仅检查 Vue 文件
npx eslint --ext .vue [文件或目录路径]

# 同时检查 JavaScript 和 Vue 文件
npx eslint --ext .js --ext .vue [文件或目录路径]
# or
npx eslint --ext .js,.vue [文件或目录路径]

Prettier

Prettier 是什么?

Prettier 是一款代码格式化工具,用于检查代码中的格式问题。

Prettier 和 ESLint 的区别?

在代码格式化方面,Prettier 确实与 ESLint 有一些重叠,但它们的重点不同。ESLint 主要用于检查代码质量并给出提示,它在格式化方面的功能有限;而 Prettier 在代码格式化方面更加全面,因此通常将它们结合使用。

安装 Prettier

在使用 vue-cli 安装 ESLint 时,Prettier 已经被安装在项目中了

Prettier 常用配置项

在项目的根目录下,创建一个名为 .prettierrc.js 的文件,用于配置 Prettier

// .prettierrc.js
module.exports = {
  printWidth: 80// 一行的字符数,如果超过会进行换行,默认为 80
  tabWidth: 4// 一个 tab 代表几个空格数,默认为 4
  useTabs: true// 是否使用 tab 进行缩进,默认为 false,表示用空格进行缩进
  singleQuote: false// 字符串是否使用单引号,默认为 true,使用单引号
  semi: true// 行尾是否使用分号,默认为 true
  trailingComma: "es5"// 是否使用尾逗号,有三个可选值"<none|es5|all>"
};

Prettier 常用命令

格式化文件

npx prettier --write [文件或目录路径]

检查文件格式

npx prettier --check [文件或目录路径]

StyleLint

StyleLint 是什么?

StyleLint 是一个用于检查和维护 CSS、SCSS 等样式表的工具。它的主要功能是确保代码风格的一致性,并检查样式表是否符合预设的规范。

安装 StyleLint

npm install stylelint --save-dev
npm install stylelint-config-standard --save-dev
npm install stylelint-config-prettier --save-dev
npm install stylelint-scss --save-dev
npm install stylelint-order --save-dev

以下是与 StyleLint 相关的插件和配置说明:

  • stylelint:StyleLint 的核心模块
  • stylelint-config-standard:StyleLint 官方推荐的配置规则
  • stylelint-config-prettier:该配置用于解决 StyleLint 和 Prettier 之间的规则冲突问题。将其放在 extends 数组的最后位置,可以确保覆盖 Prettier 的配置
  • stylelint-scss:该插件是 StyleLint 的 SCSS 扩展,增加了对 SCSS 语法的支持,允许检查和验证 SCSS 文件
  • stylelint-order:该插件强制按照指定的顺序编写 CSS 属性,可以避免属性顺序的混乱和不一致

StyleLint 配置

在项目根目录下创建名为 .stylelintrc.js 的文件来进行 StyleLint 的配置。更详细的使用可查看官方文档

StyleLint 常用命令

检查文件

npx stylelint [文件或目录路径]

修复文件

npx stylelint --fix [文件或目录路径]

最终配置

ESLint

// .eslintrc.js
module.exports = {
  root: true,
  env: {
    es6: true,
  },
  extends: [
    "eslint:recommended"// in a configuration file enables rules that report common problems, which have a check mark √ below. https://cn.eslint.org/docs/rules
    "plugin:vue/recommended"// eslint-plugin-vue/Use this if you are using Vue.js 2.x. https://github.com/vuejs/eslint-config-vue
    "plugin:prettier/recommended"// eslint-plugin-prettier/eslint-config-prettier/add prettier-eslint plugin which will uses the `.prettierrc.js` config
  ],
  parserOptions: {
    parser: "babel-eslint"// 一个对Babel解析器的包装,使其能够与Eslint兼容
  },
  rules: {
    "vue/no-v-html""off",
    "vue/html-indent""off",
    "vue/html-self-closing""off",
    "vue/max-attributes-per-line""off",
    "vue/multi-word-component-names""off",
    "vue/no-mutating-props""off",
    "vue/no-unused-vars""off",
    "no-unused-vars""off",
    "prettier/prettier""warn",
    "vue/no-unused-components""warn",
    "vue/singleline-html-element-content-newline""off",
  },
};

Prettier

// .prettierrc.js
module.exports = {
  useTabs: true,
  tabWidth: 4,
  arrowParens: "avoid",
  htmlWhitespaceSensitivity: "ignore",
  trailingComma: "es5",
};

StyleLint

// .stylelintrc.js
module.exports = {
  extends: ["stylelint-config-standard""stylelint-config-prettier"],
  plugins: ["stylelint-scss""stylelint-order"],
  rules: {
    "order/properties-alphabetical-order": null,
    "order/properties-order": [
      [
        {
          properties: ["position""top""bottom""right""left""z-index"],
        },
        {
          properties: [
            "display",
            "align-items",
            "justify-content",
            "visibility",
            "float",
            "clear",
            "overflow",
            "overflow-x",
            "overflow-y",
            "zoom",
          ],
        },
        {
          properties: [
            "list-style",
            "list-style-position",
            "list-style-type",
            "list-style-image",
          ],
        },
        {
          properties: [
            "margin",
            "margin-top",
            "margin-right",
            "margin-bogttom",
            "margin-left",
            "box-sizing",
            "border",
            "border-style",
            "border-width",
            "border-color",
            "border-top-style",
            "border-top-width",
            "border-top-color",
            "border-right-style",
            "border-right-width",
            "border-right-color",
            "border-bottom-style",
            "border-bottom-width",
            "border-bottom-color",
            "border-left-style",
            "border-left-width",
            "border-left-color",
            "border-radius",
            "border-top-left-radius",
            "border-top-right-radius",
            "border-bottom-right-radius",
            "border-bottom-left-radius",
            "border-image",
            "border-image-source",
            "border-image-slice",
            "border-image-width",
            "border-image-outset",
            "border-image-repeat",
            "padding",
            "padding-top",
            "padding-right",
            "padding-bottom",
            "padding-left",
            "width",
            "min-width",
            "max-width",
            "height",
            "min-height",
            "max-height",
          ],
        },
        {
          properties: [
            "font",
            "font-family",
            "font-size",
            "font-weight",
            "font-style",
            "font-stretch",
            "line-height",
            "text-align",
            "vertical-align",
            "white-space",
            "text-decoration",
            "text-indent",
            "text-justify",
            "letter-spacing",
            "word-spacing",
            "text-transform",
            "text-overflow",
            "word-wrap",
            "word-break",
          ],
        },
        {
          properties: [
            "color",
            "background",
            "background-color",
            "background-image",
            "background-repeat",
            "background-attachment",
            "background-position",
            "background-position-x",
            "background-position-y",
            "background-clip",
            "background-origin",
            "background-size",
          ],
        },
        {
          properties: [
            "transition",
            "transition-delay",
            "transition-timing-function",
            "transition-duration",
            "transition-property",
            "transform",
            "transform-origin",
            "animation",
            "animation-name",
            "animation-duration",
            "animation-play-state",
            "animation-timing-function",
            "animation-delay",
            "animation-iteration-count",
            "animation-direction",
          ],
        },
        {
          properties: [
            "outline",
            "outline-width",
            "outline-style",
            "outline-color",
            "outline-offset",
            "opacity",
            "filter",
            "box-shadow",
            "text-shadow",
          ],
        },
        {
          properties: [
            "content",
            "resize",
            "cursor",
            "user-select",
            "pointer-events",
          ],
        },
      ],
      {
        emptyLineBeforeUnspecified: "never",
      },
    ],
    "color-hex-case": "lower",
    "color-hex-length""short",
    "color-named""never",
    "font-weight-notation""numeric",
    "number-leading-zero""always",
    "string-quotes""double",
    "value-no-vendor-prefix": [
      true,
      {
        ignoreValues: [
          "placeholder",
          "input-placeholder",
          "text-fill-color",
          "line-clamp",
          "box-orient",
          "box",
        ],
      },
    ],
    "value-list-comma-newline-before": "never-multi-line",
    "value-list-comma-newline-after""always-multi-line",
    "value-list-comma-space-before""never",
    "value-list-comma-space-after""always",
    "declaration-colon-newline-after": null,
    "declaration-bang-space-before""always",
    "declaration-bang-space-after""never",
    "declaration-colon-space-before""never",
    "declaration-colon-space-after""always",
    "declaration-empty-line-before": null,
    "declaration-block-semicolon-newline-before""never-multi-line",
    "at-rule-no-unknown": null,
    "block-closing-brace-empty-line-before""never", // fix:@keyframes Expected empty line before closing brace
    "block-closing-brace-newline-after""always",
    "block-closing-brace-newline-before""always",
    "block-opening-brace-newline-after""always",
    "block-opening-brace-space-before""always",
    "rule-empty-line-before": [
      "always",
      {
        ignore: ["after-comment""first-nested"],
      },
    ],
    "block-no-empty": null,
    "no-empty-source": null,
    "no-descending-specificity": null,
    "selector-pseudo-class-no-unknown": null,
    "property-no-unknown": null,
    "font-family-no-missing-generic-family-keyword": null,
    "font-family-name-quotes": null,
    "selector-pseudo-element-no-unknown": null,
  },
};

拓展

与 VSCode 集成

安装 ESLint 插件

use_eslint_prettier_stylelint_img_1.jpg

安装 Prettier 插件

use_eslint_prettier_stylelint_img_2.jpg

安装 Stylelint 插件

use_eslint_prettier_stylelint_img_3.jpg

在 VSCode 中安装 ESLint、Prettier 和 Stylelint 插件可以实现在编写代码时自动进行代码检查和格式化。

推荐设置如下:

{
  // 设置全部语言在保存时自动格式化
  "editor.formatOnSave": true,
  // 保存时使用 StyleLint 修复可修复错误
  "stylelint.autoFix": true,
  // 设置全部语言的默认格式化程序为prettier
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}
全部评论
写得很好,补充一个细节,off,warn,error是string类型,而对应的0,1,2是number类型,不要加引号也当做string了。
点赞 回复 分享
发布于 2024-01-01 19:15 广西

相关推荐

04-03 12:09
東京大学 C++
点赞 评论 收藏
分享
评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客企业服务