四、样式代码规范的工具——stylelint

774 阅读6分钟

1. 介绍

注:本小结内容总结自英文官网

  • 一句话介绍:A mighty, modern linter that helps you avoid errors and enforce conventions in your styles. (一个强大的、现代化的格式化工具,它可以帮助你避免样式代码里的错误,并强化你样式代码的格式)
  • 强大之处
    • 有超过 170 条内置规则
    • 提供插件支持,这样你就可以定制你自己的规则了
    • 会尽可能地自动修复问题
    • 源码有超过 15000 个单元测试
    • 支持可共享的配置
    • 非自主的,你可以根据你确切的需求来进行完全的定制
    • 像 prettier 一样,提供了很棒的结果输出
    • Google、GitHub、WordPress 都在使用,社区正在逐渐成长
    • 可以扩展到以下场景:
      • SCSS, Sass, Less, SugarSS 等 CSS 预处理语言的语法
      • HTML, Markdown 中的行内样式
      • CSS-in-JS 对象
      • 模板语法中的行内样式

2. 安装

在安装依赖前,推荐先在 IDE 里集成 Stylelint 插件,详细流程请查阅:附:IDE 集成 Stylelint 插件

首先安装 stylelint

npm i stylelint -D # npm
yarn add stylelint -D # yarn
pnpm i stylelint -D # pnpm

安装好这个依赖之后,即可对 stylelint 进行配置,但为了简化用户的使用,官方提供了一个标准插件 stylelint-config-standard 来为用户提供官方推荐的配置,因此我们也可以安装这个插件

npm i stylelint-config-standard -D # npm
yarn add stylelint-config-standard -D # yarn
pnpm i stylelint-config-standard -D # pnpm

此外,官方还推荐了其他的插件:

  • stylelint-config-prettier
  • stylelint-config-standard-scss (SCSS 项目使用)
  • stylelint-config-recommended-less (LESS 项目使用)

3. 配置

3.1 配置方式

stylelint 支持的配置方式有:

  • package.json 中的 stylelint 配置项
  • .stylelintrc 文件 (语法可以是 JSON 也可以是 YAML)
  • stylelint.config.js 文件
  • stylelint.config.cjs 文件 (package.json 中的 "type": "module" 时)
  • .stylelintrc.js 文件
  • .stylelintrc.json 文件
  • .stylelintrc.yaml/stylelintrc.yml 文件

3.2 配置项

配置项描述取值类型
rules详见 3.4 Rules详见 3.4 Rules
extends指定应用的配置源字符串或字符串数组
plugins一些 rules 的集合字符串或字符串数组
customSyntax指定自定义的语法解析器字符串
overrides为特定的文件指定特定的规则对象数组
defaultSeverity默认的严重等级字符串
report*Disables详见 3.3 report*Disables详见 3.3 report*Disables
ignoreDisables是否忽略 stylelint-disable 注释布尔值
ignoreFiles忽略的文件字符串或字符串数组
支持 glob 匹配
processorsstylelint 解析器配置字符串或字符串数组

3.3 report*Disables

stylelint 提供了三个 report*Disables 的配置项:

  • reportDescriptionlessDisables
  • reportInvalidScopeDisables
  • reportNeedlessDisables

这三个配置项用于给 stylelint-disable 注释提供额外的校验,以增强注释的文档性。
这三个配置项的取值有三类:

  • null:关闭这个规则
  • true | false:主配置
  • 带有两个成员的数组
    • 第一个成员:主配置,值为 true | false
      • true:只为指定的规则启用这个配置
      • false:只为指定的规则禁用这个配置
    • 第二个成员:一个对象,具有 exceptseverity 属性
      • except:一个数组,数组的每个成员都是一条规则名称
      • severity:提示等级,取值为 warning | error

3.4 Rules

stylelint 提供了超过 170 条可配置的规则,这些规则都配置于配置文件的 rules 配置项中,这个配置项的 key 即为规则的名称,value 有如下取值类型:

  • null:关闭这个规则
  • 单一的一个值,这个值可以是数组、字符串、布尔值等,作为规则的主配置
  • 带有两个成员的数组
    • 第一个成员:主配置,一个单一的值,这个值可以是数组、字符串、布尔值等
    • 第二个成员:次配置,一个对象

注意:stylelint 没有任何一个规则是默认启用的,也没有任何一个规则有默认值,因此你必须精准地对每一条规则进行配置,以启用对应的规则

每一条规则的次配置可以包含如下四个通用的属性:

  • disableFix:值为 true | false | null,为这个规则指定是否禁用自动修复
  • message:值为一个字符串或返回字符串的函数,为这个规则配置自定义的错误提示
  • reportDisables:值为 true | false | null,为这个规则指定是否打印 stylelint-disable 注释提示,对规则内置的提示仍然有效
  • severity:值为 warning | error,为这个规则指定错误等级

stylelint 提供的规则非常多,所有的规则请参见 官方文档 Rules 部分

4. 使用

编写配置文件 .stylelintrc.js 如下

module.exports = {
  extends: [
    "stylelint-config-prettier",
    "stylelint-config-recommended-less",
    "stylelint-config-rational-order",
  ],
  plugins: ["stylelint-order", "stylelint-declaration-block-no-ignored-properties"],
  overrides: [
    {
      files: ["*.less", "**/*.less"],
      customSyntax: "postcss-less",
    },
  ],
  rules: {
    "declaration-colon-space-after": "always-single-line",
    "declaration-colon-space-before": "never",
    "declaration-block-trailing-semicolon": null,
    "rule-empty-line-before": ["always", { ignore: ["after-comment", "first-nested"] }],
    "plugin/declaration-block-no-ignored-properties": true,
  },
};

通常来说,Stylelint 也是和 lint-staged 配合来使用的,因此只需在 lint-staged 配置里多加一个配置项即可:

{
  "lint-staged": {
    "*.{css,less}": "stylelint --fix"
  },
}

如果你期望在 Vue 项目中使用 Stylelint,且可以用 Stylelint 来格式化 .vue 文件里的样式代码,那么就需要集成 postcss-html 这个库,并按对应的文档进行配置,然后就可以把上面 lint-staged 的配置改为:

{
  "lint-staged": {
    "*.{vue,css,less}": "stylelint --fix"
  },
}

相关资源

Sherry Standard Stylelint

根据我自己的开发习惯,我封装了一个自己的 Stylelint 配置——@sherry-standard/stylelint,有了这个包之后,我只需要在项目里安装 Stylelint 和这个包,再在 package.json 里增加如下配置,就可以快乐地使用 Stylelint 了。

{
  // 其他配置
  "stylelint": {
    "extends": [
      "@sherry-standard/stylelint"
    ]
  },
  // 其他配置
}

Stylelint 配置项

注:如果想查阅官方的类型定义文件,可直接查阅 import("stylelint").Config 这个类型。

查阅官方文档,总结了 Stylelint 提供的配置项,以及每一项对应的含义:

declare namespace Stylelint {
  type Severity = "warning" | "error";

  type AnyType =
    | Record<string | number | boolean, any>
    | ((...args: any[]) => any)
    | any[]
    | Map<any, any>
    | Set<any>
    | string
    | symbol
    | bigint
    | number
    | boolean
    | undefined
    | null;

  /**
   * 主配置
   */
  type PrimaryOption<T> = T;

  /**
   * 次配置
   */
  interface SecondaryOption {
    /**
     * 是否禁用自动修复
     */
    disableFix?: null | boolean;
    /**
     * 自定义的错误提示
     */
    message?: string | ((...args: any[]) => string);
    /**
     * 是否打印 stylelint-disable 注释提示,对规则内置的提示仍然有效
     */
    reportDisables?: null | boolean;
    /**
     * 错误等级
     * @values warning
     * @values error
     */
    severity?: Severity;
    [key: string | number | symbol | bool]: any;
  }

  declare interface Rules {
    [key: string]: null | PrimaryOption<AnyType> | [PrimaryOption<AnyType>, SecondaryOption];
  }

  declare type Override = Omit<StylelintConfig, "overrides"> & {
    /**
     * 指定配置的文件名,支持 glob 匹配
     */
    files: string | string[];
  };

  interface ReportDisablesSecondaryOption {
    /**
     * 一个数组,数组的每个成员都是一条规则名称
     */
    except: string[];
    /**
     * 提示等级
     */
    severity: Severity;
  }

  declare type ReportDisables =
    | null
    | PrimaryOption<boolean>
    | [PrimaryOption<boolean>, ReportDisablesSecondaryOption];

  declare interface StylelintConfig {
    /**
     * @description 指定应用的第三方配置
     * - 可以是配置文件的相对路径
     * - 可以是 node_modules 里的第三方库名
     */
    extends?: string | string[];
    /**
     * @description 指定应用的第三方规则
     * - 通常是 node_modules 里的第三方库名
     */
    plugins?: string | string[];
    /**
     * 指定自定义的语法解析器
     */
    customSyntax?: string;
    /**
     * 为不同的文件指定不同的配置
     */
    overrides?: Override[];
    /**
     * 指定全局默认的错误等级
     * @values warning
     * @values error
     */
    defaultSeverity?: Severity;
    /**
     * 报告没有描述的 `stylelint-disable` 注释
     */
    reportDescriptionlessDisables?: ReportDisables;
    /**
     * 报告不满足配置文件中配置的规则的 `stylelint-disable` 注释
     * - 启用这个配置时,如果某条 `stylelint-disable` 注释的规则与配置文件中不一致,stylelint 将报告这条注释
     */
    reportInvalidScopeDisables?: ReportDisables;
    /**
     * 报告 `stylelint-disable` 注释
     */
    reportNeedlessDisables?: ReportDisables;
    /**
     * 是否忽略 `stylelint-disable` 注释
     */
    ignoreDisables?: boolean;
    /**
     * stylelint 不检查的文件
     * - 支持 glob 匹配
     */
    ignoreFiles?: string | string[];
    /**
     * stylelint 的解析器
     */
    processors?: string | string[];
    /**
     * 自定义规则的集合
     */
    rules?: Rules;
  }
}