微信号:gh_ffb279ea1674

介绍:《奇舞周刊》是由奇舞团维护的前端技术周刊.每周五向大家推送前端技术文章.

Stylelint: 我们日夜期盼的样式表Linter

2017-09-02 18:09 garnett 译

编者按:本文由garnett在众成翻译平台上翻译。

每一个程序员,无论他是写哪一门语言的,都希望自己写出干净整洁、一致性好的代码。因此很多开发者习惯于对诸如JavaScript和Python一类的编程语言启用linter,但是却很好少有人使用linter来规范样式表。那么在这篇文章中,就让我们来一睹stylelint1(一个应用于样式表的linter)的真面目。

同时我们也将了解到在样式表中启用校对的关键性,以及它是如何让一个样式表有序和避免错误的。最后,我们将学会如何使用stylelint并尽快上手。

Linting很重要你知道么

linter就是当一段代码没有通过定义在配置文件中的校验规则时,能够分析代码并报出错误的工具。

我们之中的很多人都在代码库上面做开发,与你一同在上面开发的还有很多你的同事。如果没有一个严格的代码风格校对规则的话,代码很快就会成为一滩shxt。也许你的代码已经是这种情况了,而意识到这一点的你想要修整一下代码并维持住代码的整洁。即使你只是写样式表,你也依然希望代码能够具有很高的一致性。

没错,你的团队可能在某个地方的某条纯文本wiki中记录了团队的代码样式规范。但是,不容忽视的是人的因素:人总是会犯错——总是在无意之间。

而且即使你很自律地执着遵循某个规范的代码风格,但是你没办法确保你的同事或是你的开源项目的贡献者能够像你一样。没有linter的帮助,你必须人工检查代码样式和错误。而机器存在的意义就是代替人来完成能够自动化实现的任务。linter就是这样的机器,有了linter,你不需要浪费时间检查代码风格,也不需要对每一个代码错误都写一大堆的注释,因此它能够极大程度地减少你花费在代码审阅上的时间。你无须检查代码究竟做了些什么,也无需关心它看起来什么样。

Stylelint

Stylelint是一个由David ClarkRichard HallowsEvilebot Tnawi社区共同用JavaScript开发的现代样式表linter。它在速度、多样性和校验规则质量等方面都有着不凡的表现,更重要的是,它是可私人订制的。Stylelint有一百多条的校验规则,并且还在逐步增加。稳住别怕,尽管如此,但是他们都是默认关闭的,你可以只开启你感兴趣的那些校验规则。除了能够校验CSS外,Stylelint对于Sass, SugarSS和其他任何PostCSS能够解析的语法(因为Stylelint就是基于此的)都同样适用。

stylelint之于样式表就像ESLint之于JavaScript。

校验规则

刚刚提到,stylelint有一百多条校验规则, 这些规则可以分为三类:用于校对风格的规则、用于判别代码可维护性的规则、以及用于判断代码错误的规则。用于风格校验的规则主要针对空格(比如说冒号附近的空格)、换行、缩进等等。用于判别代码可维护性的规则会判断在CSS选择器中是否有使用某个ID,或者在某条声明当中是否应用了!important关键词。用于判断错误的规则会检测错误的HEX颜色写法或者某条简写属性是否会覆盖其他的声明语句。

对于代码风格判别的规则,其实很好理解,所以在此不做赘述。而我真正想详细介绍的是,用于判别代码可维护性和判断错误的校对规则。

比如说,防止简写属性覆盖其他声明的规则(或者,按照stylelint的官方表述,declaration-block-no-shorthand-property-overrides)将阻止像下面这样书写代码:

div {

    padding-left: 20px; /* This property is overridden. */

    padding: 10px;

}

Stylelint也能防止不可用的HEX颜色写法 (color-no-invalid-hex):

{

    color: #44;

}

同时,它还能避免出现如下的属性重复的情况(declaration-block-no-duplicate-properties):

{

    color: #000; /* This property is overridden. */

    margin: 0 0 1.25em;

    color: #777;

}

或许你会在样式表中使用旧的梯度语法。Stylelint将会检测到这一点(function-linear-gradient-no-nonstandard-direction):

/* incorrect property */

.block {

    background: linear-gradient(bottom, #fff#000);

}


/* correct property */

.block {

    background: linear-gradient(to bottom, #fff#000);

}

在某条声明中使用了!important关键字的话,会在你需要用其他规则覆盖当前声明时遇到问题。对于这种情况,需要使用declaration-no-important规则来避免在代码中书写!important

在CSS选择器当中使用ID的同时使用标签选择器(基于HTML元素的选择器,举例来说,.block p就是),这样的写法在诸如BEM等方式中不允许的。面对这样的问题, selector-no-idselector-no-type能够助你一臂之力。

有时你难免会拼写错误或者漏写一些样式表规则。以动画为例, no-unknown-animations 就会帮你指出是否缺少与某个动画名相对应的@keyframes规则。

你是否还在为给属性名、属性值和选择器添加大堆的前缀而烦恼不堪?把这一切交给Autoprefixer。Autoprefixer 会代替你完成这件任务,并且可以借助value-no-vendor-prefixproperty-no-vendor-prefixselector-no-vendor-prefix这样的规则决定是否添加前缀。

毫无疑问,上述只是冰山一角,更多stylelint的校验规则请阅读原文。

插件

除了前面介绍的默认规则外,stylelint还支持各种插件,方便开发者扩展它的功能。尽管现在可用的插件还不多, 但是出品必属精品。

一些开发者喜欢写嵌套的样式表语句。尽管目前所有的CSS预处理器已经支持了嵌套写法,但是如果嵌套很深的话会导致选择器的特异性提高,进而导致维护代码困难的问题。如下就是一个典型的例子:

.header {

    .nav {

        .item {

            .link {

                color: blue;


                &:hover {

                    color: red;

                }

            }

        }

    }

}

上述代码渲染的结果是:

.header .nav .item .link {

    color: blue;

}

.header .nav .item .link:hover {

    color: red;

}

Stylelint 对于上述问题没有一个很好的解决方案,但是有一个插件 (stylelint-statement-max-nesting-depth) 可以对嵌套深度增加约束规则。

任何插件在使用之前都需要先安装:

npm install stylelint-statement-max-nesting-depth --save-dev

接下来,在配置文件中的plugins数组中添加上安装好的插件。按如下方式增加新的规则,并配置它:

{

    "plugins": [

        "stylelint-statement-max-nesting-depth"

    ],

    "rules": {

        "statement-max-nesting-depth": 2

    }

}

在上面的配置中,我们设定嵌套深度只能到2。所以我们会被提示去减小上面例子中的嵌套深度(在这个例子中,就是2级):

.nav {

    .link {

        color: blue;


        &:hover {

            color: red;

        }

    }

}

或者我们干脆将它减少到1级:

.nav-link {

    color: blue;


    &:hover {

        color: red;

    }

}

篇幅有限,我无法对每个插件都一一详述,只能推荐其中几个:

  • Prevent qualified selectors, such as ul.nav, div#main and input[type="submit"]. (Each option can be enabled separately.)

  • 强制书写简写值

  • 如果你正在采用BEM或者SUIT的书写规则,那么你可能需要检查一下你的选择器是否按照这些标准正确书写了。stylelint-selector-bem-pattern这个插件已经预定义了BEM和SUIT的规则,并且可以为其他的书写规范做类似的配置。

如果你想自定义一条新的校验规则,你可以写一个你自己的插件.

配置文件

配置是使用一个linter最困难也是最耗时的环节。但是有一些捷径和不同的策略让stylelint配置起来更加简单。

你的配置文件可能会慢慢变得越来越大,所以最便捷的方式就是将stylelint的配置存储在一个单独的名为.stylelintrcJSON文件当中。这样的话,这个文件就可以在终端或者代码编辑器中以命令行的方式使用了。

一个简单的配置看起来应该是这样的:

{

    "rules": {

        "color-hex-case": "lower",

        "color-hex-length": "short",

        "color-no-invalid-hex": true

    }

}

三种配置的方式第一种,很简单,就是去扩展别人的配置,对你要改变的规则做一些增删。一些开发者已经构建了能够满足绝大多数情况的配置文件。你只需要将它作为npm包安装就好了:

npm install stylelint-config-standard --save-dev

接下来,就是在你自己的配置文件中,对规则做扩展或是覆盖:

{

    "extends": "stylelint-config-standard",

    "rules": {

        "indentation": "tab",

        "number-leading-zero": null

    }

}

在上面的例子中,我们扩展了stylelint-config-standard,将indentation修改为 “tabs” ,并禁用掉了number-leading-zero

你不仅能扩展通过npm安装的配置文件,本地的配置文件同样能够扩展。这个文档中有更多关于扩展和共享配置的介绍。

第二种配置的方式是以一个空文件为起点,一点点增加你需要的校对规则。比如如下场景就比较适合,目前你并不关注代码风格校对,只是希望能够避免出错:

{

    "rules": {

        "color-no-invalid-hex": true,

        "declaration-block-no-duplicate-properties": true,

        "declaration-block-no-shorthand-property-overrides": true,

        "function-linear-gradient-no-nonstandard-direction": true

    }

}

后续你可以添加更多的规则。

第三种方式就是对所有规则看个遍,一条一条地配置。我个人比较倾向于这种方式,因为我可以尽可能多地应用校验规则,最大程度上发挥stylelint的威力。毫无疑问,这是最耗时的方式,但是却能获得最好的效果。不过为了让这种方式更加简化,stylelint的开发者们创建了一个带有所有规则的配置文件的例子

每一条开启的规则都有报错的等级。这意味着任何不符合的规则都将使实例失效。每条规则报错的等级都可以降低成为警告,这样做不会让实例失效。这十分适合在项目中新引进了某个规则却不想在构建过程中使项目失效的情境。

{

    "rules": {

        "color-hex-case": ["lower", { "severity": "warning" }]

    }

}

在上面的例子当中,stylelint会在HEX颜色书写错误时发出警告而不是报错。

有些时候,尽管我们的stylelint配置文件中明令禁止了某种写法,但是我们却想在样式表中这样去写。比如,配置文件中禁止样式表中出现!important关键字,但是我们需要用它去覆盖某个第三方的部件的样式。但是我们不希望因为这样一个例外而关闭掉这条校验规则。但同时我们也不想每一次都看到报错提示(人就是这么纠结。。)还好,我们可以在CSS的某一行代码中添加一条注释来禁用规则

.widget {

  display: none !important; /* stylelint-disable-line declaration-no-important */

}

或者我们可以禁用一块CSS的stylelint:

/* stylelint-disable */

.third-party-code {}

/* stylelint-enable */

使用

Stylelint 有很多的使用方法: 在命令行中、在诸如Gulp、Grunt、Webpack的构建工具中、在代码编辑器中或者是作为Git pre-commit hook 用于Git仓库中的修改。我将重点介绍ruxia两种方式。

命令行

在你想要在没有添加stylelint的项目中开启校验,或者是希望在npm脚本当中使用stylelint的话,命令行工具会是一个很好的选择。

全局安装stylelint:

npm install stylelint -g

然后,stylelint在终端的每个地方都可以使用:

stylelint "styles/**/*.css"

上面这条命令会校对styles 目录及其子目录下面的所有CSS文件。

如果要校验SCSS或者是SugarSS文件,需要添加syntax选项:

stylelint "styles/*.scss" --syntax scss

也可以明确指定配置文件:

stylelint "styles/*.css" --config bar/myStylelintConfig.json

如果未明确指定,那么stylelint将在当前工作目录中查找.stylelintrc文件。

Gulp

要在Gulp中将stylelint用作PostCSS插件使用的话,需要安装以下软件包:

npm install gulp-postcss stylelint postcss-reporter --save-dev

gulp-postcss是针对所有PostCSS插件的运行器, postcss-reporter会更加友好地报出来自stylelint的警告和错误提示。

var postcss = require('gulp-postcss');

var reporter = require('postcss-reporter');

var stylelint = require('stylelint');


gulp.task('lint:css', function() {

    return gulp.src('src/**/*.css')

        .pipe(postcss([

            stylelint({ /* options */ }),

            reporter({ clearMessages: true })

        ]));

});

输出如下:

终端窗口显示的来自stylelint Gulp任务的结果

要校验CSS语法以外的样式表,需要安装适当的语法。比如,要校验SCSS的话,需要安装postcss-scss30:

npm install postcss-scss --savedev

然后,配置gulp-postcss来使用以下语法:

var postcss = require('gulp-postcss');

var reporter = require('postcss-reporter');

var stylelint = require('stylelint');

var scss = require("postcss-scss");


gulp.task('lint:css', function() {

    return gulp.src('src/**/*.scss')

        .pipe(postcss(

            [

                stylelint({ /* options */ }),

                reporter({ clearMessages: true })

            ],

            {

                syntax: scss

            }

        ));

});

您可以明确指定配置文件;否则,stylelint将会查找.stylelintrc。

结论

Stylelint312是一个性能强劲的样式表linter。它能够清晰地显示代码,让你减少犯错。它对每个人都是有用的,无论是个人开发人员,团队还是开源项目维护者。一旦你开始使用它,你就再也不会听到这样的声音,“你忘了在这里添加一个空格”或者“你忘了在那删除它。”有了它,能让你体验到开发愉快的感受,同时让代码审查更加平和轻松。


奇舞周刊

——————————————————

领略前端技术 阅读奇舞周刊


长按二维码,关注奇舞周刊

 
奇舞周刊 更多文章 奇舞周刊第 225 期:大前端的转变之路 使用 Flow 进行类型检查 何时使用立即执行函数表达式 使用 Paint Timing API 度量性能 几张图带你揭秘一个超快的 CSS 引擎
猜您喜欢 QQ物联H5界面控制界面快速入门 你要的种子这里都有,只是得躲过5000头饿熊,方圆300里禁止生育,死亡违法... 关于Docker你不知道的事——什么是Docker 吴甘沙:大数据的六大人工智能变现方式 程序员要学会读源代码