stylelint 接入实战踩坑总结

6,628 阅读11分钟

前言

团队合作时,当每个人的代码都拥有自定义的格式化方式时,在提交merge的时候往往要解决很多冲突,此时我们可以使用eslint+stylelint来对团队的代码进行约束。eslint的配置引入比较简单,网上有比较多的教程,而stylelint的教程大多语焉不详。在这里,我会介绍一下我在引入stylelint所遇到的坑,以及解决方法。

正文

stylelint是一个强大的,现代的代码检查工具,可以帮助你在团队合作中强制执行样式约定

1. 安装stylelint

yarn add -D stylelint

2. 配置文件

使用 stylelint检测器需要一个配置对象,你可以使用三种方式来创建这个对象。

  • package.json 中的stylelint 属性。
  • .stylelintrc.js文件
  • stylelint.config.js 文件输出的js对象

一旦发现它们中的任何一个,将不再继续进行查找,进行解析,将使用解析后的对象。 本次使用的是.stylelintrc.js 文件来进行配置。

3. 使用stylelint

安装官方文档的说法你可以按照以下方法运行stylelint检测样式代码。

--fix 用来自动修复,但不能修复所有的问题。

// package.json
"scripts":{
  "lint:css":"stylelint src/**/*.css --fix"
}

踩坑点1:

由于我的项目里使用的样式语言是less。所以检测css是肯定不对的,所以这里我们需要做一点改动

// package.json
"scripts":{
  "lint:css":"stylelint src/**/*.less --fix"
}

于是我们可以运行这串代码了

yarn lint:css postcss-less

image.png

大家可以看到,这里报了一些提醒,简单翻译为让我们用对应的语法去解析我们的样式。而这对应的语法解析器是需要我们去安装的。

yarn add -D   postcss-less

于是再次对脚本进行修改。

// package.json
"scripts":{
  "lint:css":"stylelint src/**/*.less --fix  --custom-syntax postcss-less"
}

OK 到这里我们就可以正常的去跑lint命令对我们的样式代码进行格式化了。接下来我们来配置lint规则

4. 配置规则

stylelint目前是有些工作者帮忙翻译出了中文文档,如果对阅读英文文档有一定排斥性的同学可以查看中文文档

我们首先需要安装三个npm包帮助我们完善规则

yarn add -D stylelint-config-standard stylelint-order stylelint-config-css-modules

stylelint-config-standard 是stylelint的推荐配置,stylelint-order是用来在格式化css文件时对代码的属性进行排序。 stylelint-config-css-modulescss-module的方案来处理样式文件

我的配置文件长这样:

// .stylelintrc.js
module.exports = {
    processors: [],
    plugins: ['stylelint-order'],
    extends: [
        "stylelint-config-standard",
        "stylelint-config-css-modules"
    ],
    rules: {
        "selector-class-pattern": [ // 命名规范 -
            "^([a-z][a-z0-9]*)(-[a-z0-9]+)*$",
            {
                "message": "Expected class selector to be kebab-case"
            }
        ],
        "string-quotes":"single", // 单引号
        "at-rule-empty-line-before": null,
        "at-rule-no-unknown":null,
        "at-rule-name-case": "lower",// 指定@规则名的大小写
        "length-zero-no-unit": true,  // 禁止零长度的单位(可自动修复)
        "shorthand-property-no-redundant-values": true, // 简写属性
        "number-leading-zero": "never", // 小数不带0
        "declaration-block-no-duplicate-properties": true, // 禁止声明快重复属性
        "no-descending-specificity": true, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器。
        "selector-max-id": 0, // 限制一个选择器中 ID 选择器的数量
        "max-nesting-depth": 3,
        "indentation": [2, {  // 指定缩进  warning 提醒
            "severity": "warning"
        }],
        "order/properties-order": [ // 规则顺序
            "position",
            "top",
            "right",
            "bottom",
            "left",
            "z-index",
            "display",
            "float",
            "width",
            "height",
            'max-width',
            'max-height',
            'min-width',
            'min-height',
            'padding',
            'padding-top',
            'padding-right',
            'padding-bottom',
            'padding-left',
            'margin',
            'margin-top',
            'margin-right',
            'margin-bottom',
            'margin-left',
            'margin-collapse',
            'margin-top-collapse',
            'margin-right-collapse',
            'margin-bottom-collapse',
            'margin-left-collapse',
            'overflow',
            'overflow-x',
            'overflow-y',
            'clip',
            'clear',
            'font',
            'font-family',
            'font-size',
            'font-smoothing',
            'osx-font-smoothing',
            'font-style',
            'font-weight',
            "line-height",
            'letter-spacing',
            'word-spacing',
            "color",
            "text-align",
            'text-decoration',
            'text-indent',
            'text-overflow',
            'text-rendering',
            'text-size-adjust',
            'text-shadow',
            'text-transform',
            'word-break',
            'word-wrap',
            'white-space',
            'vertical-align',
            'list-style',
            'list-style-type',
            'list-style-position',
            'list-style-image',
            'pointer-events',
            'cursor',
            "background",
            "background-color",
            "border",
            "border-radius",
            'content',
            'outline',
            'outline-offset',
            'opacity',
            'filter',
            'visibility',
            'size',
            'transform',
        ],
    }
};
  • processors 属性由于此次并没有使用,所以不做介绍,有兴趣的同学可以查询官方文档。
  • plugins 是由社区创建的规则或规则集,支持方法论、工具集,非标准 的 CSS 特性,或非常特定的用例。
  • extends 继承一个已存在的配置文件。(在我的配置中,继承了css-module和官方推荐的配置)
  • rules 规则决定检测器要查找什么和要解决什么,所以,通过该选项你就可以开启相应规则,进行相应的检测。所有规则必须显式的进行配置,因为 没有默认值

另外还有 defaultSeverityignoreFiles也可以在这里配置,有需要的同学可以在文档中找到。

由于我在配置文件中已经对相应规则做了注释,解释了他的作用,如果有同学对此有疑问,欢迎留言或者加我好友进行交流~

注意: null为禁用规则。可以在rules里面重写覆盖官方推荐的配置规则。

5. 忽略lint文件

此时我们已经可以正常的使用stylelint来格式化样式代码了。但是在项目中往往会存在一些不需要格式化的代码,比如我们会单独抽离一个overrides文件来重写antd的样式。显然这里是不需要格式化的,因为antd的选择器命名可能跟我们的规范不尽相同。所以我们需要在运行lint时忽略这个文件。

    1. 我们可以在.stylelintrc.js中配置ignoreFiles
    1. 创建.stylelintignore文件。
    1. 我们可以通过 /* stylelint-disable */的方法,来对代码快进行忽略lint检测。

我采用的是第二种方法,配置如下:

// .stylelintignore
*.js
*.tsx
*.ts
*.json
*.png
*.eot
*.ttf
*.woff
*.css
src/styles/antd-overrides.less

6. 自动格式化

在进行完上文的配置之后,其实我们已经达到了规范的目的,但是如果每次都要跑一次lint无疑就会加重我们的编码负担。这里介绍两种方式在我们写样式代码时,对代码自动格式化的方法。

6.1 stylelint vs-code 插件

我们可以在vs-code插件市场中搜索stylelint插件,它大概长这个样子

image.png

可以看到我这里是黑色的,这是因为我不用这个插件,它有一些bug。

简单介绍一下bug所在:

在antd-overrides中有一些代码过了我们配置的lint规则,但是没有这个插件会给我们报一个CssSyntaxError。而且在删除一些问题代码之后,这个插件还会报一些逻辑代码错误。这是我不能接受的。于是果断弃用。大家可以按照自己项目实际情况进行选择~

6.2 webpack plugin

你可以很轻松的找到webpack的stylelint-plugin。代表这个插件已经广泛使用~你可以放心的接入。

为什么一个webpack插件可以帮助我们格式化样式代码呢,这是因为我们在热更新重新编译的时候,这个插件会帮我们检测代码。并根据.stylelintrc.js文件中配置的规则进行fix。 如果有lint错误可以选择让项目无法运行,避免将没有lint的样式上传到代码库。

于是我在使用这个插件的时候踩了好多坑,接下来我一一的说。

6.3 插件踩坑集锦

最开始时。按百度到的各路大神的写法,只需要这么配置就可以:

new StyleLintPlugin({
    context: "src",
    configFile: path.resolve(__dirname, './stylelintrc.js'),
    files: '**/*.less',
    failOnError: false,
    quiet: true,
    syntax: 'less'
})

结局不出意料,没有用。最恐怖的是他会给你一种假象,你本地运行的时候没有任务问题,让你误以为你的代码没有任何问题!其实,是这个插件没有作用到。

另外这么配置如果使用stylelint的vscode扩展时,还会有一大堆的让你心态爆炸的红波浪~~~~

经过我的踩坑,终于完成了一个没有报错,没有假象,没有错误检查,没有忽略我的忽略配置的配置!

    new StylelintPlugin({
      configFile: path.resolve(__dirname, './.stylelintrc.js'),
      extensions: ['less'],
      files: 'src/**/*.less',
      fix: true,
      customSyntax: 'postcss-less',
      lintDirtyModulesOnly: true,
      threads: true,
      exclude: ['node_modules', 'src/styles/antd-overrides.less'],
    })

这里我想详细的解释一下各字段的用法。

  • configFile 没什么好说的,加载配置文件。
  • extensions 指定要检查的扩展名。 这里一定要配置,不然会去检测你的tsx。
  • files 指定检测目录。
  • fix 这个是重点。这就是自动格式化的关键配置所在。
  • customSyntax 这又是关键!!!! 一定要加这个配置,百度到的大佬配置中使用的是syntax。这个配置已经过时了,需要使用customSyntax,并且value一定要是你之前安装过的postcss-less包。这个配置竟然连webpack官方文档中都没有。我已经准备去提issue了
  • lintDirtyModulesOnly仅检查有变化的文件,启动时跳过检查。
  • threads 会根据 cpu 的数量自动决定池子的大小。
  • exclude 这个非常重要。因为我在实践中发现webpack-plugin没有读取我在.stylelintignore中配置的忽略规则,而导致项目在运行时报了一大堆错误。一定要配!!!!

7. commit检测

这个就比较简单了,如果项目之前配置过eslint时的commit检测,这里只需要在脚本中加入检测样式就可以。配置如下

  "lint-staged": {
    "*.{ts,tsx}": [
      "eslint --ext js,ts,tsx --fix",
      "git add"
    ],
    "*.less": [
      "stylelint --fix  --custom-syntax postcss-less",
      "git add"
    ]
  }

这里其实是不需要跑yarn lint:css的,因为如果这样在commit时会全量检测所有src下的样式,然而其实我们只需要检测修改的文件即可。特别注意: 一定要加上 --custom-syntax postcss-less

好了,到这里我们就。。。。还没结束。

我们来梳理一下stylelint的工作流程

  • .stylelintrc配置规则。
  • package.json配置脚本命令
  • .stylelintignore配置忽略规则
  • stylelint-webpack-plugin配置自动格式化规则
  • lint-staged配置commit规则

首先运行项目时会去读取.stylelintrc文件,并根据里面的规则通过webpack-plugin去检查代码,自动格式化。在运行 lint:css时,会读取.stylelintignore检测时忽略相关文件。在修改完代码后commit时lint-staged会帮我们在做一次提交前检测,避免上传没有格式化的代码。

7.1 梳理流程时发现的坑

在我做完stylelint相关配置之后,开始了激情编码环节。然而我根据设计图去给元素设置一个带有透明度的颜色rgba时。贴心的插件就会帮助我,把rgba格式化成rbg颜色。像这样:

image.png

自动格式化后,嘟 变成了这样

image.png

rgb(0 0 0 / 12%) 这是什么东西? 起初我并不在意,直到我发现了在页面上这个样式变成了这样

image.png

这不是逗我吗,你格式化就格式化,怎么变成了这玩意???

image.png

于是连忙去百度,百度不到答案。。。然后又谷歌,终于找到了一个看起来像答案的答案

image.png

简单解释一下。这是一个比较新的css规范。sass规范还不支持。类比到我的less。也就是我的less规范还不支持。因为项目里用的less版本是3+。还不是最新的。所以不支持简直是再正常不过的事。我的less把我的新规范的带透明度的rgb识别成了第三个参数后面的/是除法。0除以12%大声告诉我是多少?还是0吧

所以我的less没有错 错的是这个世界!

报着尝试的心态我去浏览器直接写了一个rgb(0 0 0 / 12%) 看看支不支持。结果如下:

image.png

没错,浏览器支持!那好办了,摆在我们面前有两个解决方法

  1. 让less支持这种色值方案
  2. 让stylelint不格式化

image.png

带着方法我去查找了less的官方仓库的 changelog 我妄图尝试在最新版的更新里哪怕提到半个rgb的字眼,然而并没有。也可能是我的眼神不太好~~ 。 总之第一条方法失败了。

那么我们用第二种方法,首先要知道是stylelint的哪条规则把rgba格式化成了rgb。我做了大量的尝试。并且做了大量的百度。不出我所料。百度不到。尝试也都不对。路走窄了。

于是我换了一个思路,我去看看官方推荐的stylelint-config-standard 配置库。如图:大家注意红框

image.png

在23版本时,颜色已经是百分比了。这也是最新版本,也是我项目里的版本。那么可以确定的是,一定是这个库帮我格式化了!!!

那么我们该怎么让他不格式化呢?去查看这个库其他的版本,但凡哪个版本里出现了rgba,那他这个版本就不会自动格式化。

功夫不负有心人。我只找了一个版本,就找到了

image.png

于是对项目里的库版本做降级处理~ ,这样就不会把rgba格式化成rgb了! 大功告成。

后记

rgba的问题还有一些其他的解决方案,有兴趣的可以观看下方评论,有大佬提供了更优解。