Stylelint
Как и зачем линтить CSS
Андрей Ситник,
Злые марсиане
Наш опенсорс
История человечества
10К
40К
250К
Неолитическая революция
История линтеров
Исходный код
Парсер
Анализ
Список ошибок
Линтер
1978 — первый линтер Lint
1995 — JavaScript
// true
1 == "1"
// забыт var
count = 1
Линтеры
CoffeeScript
или
CoffeeScript :-(
Эволюция линтеров
JSLint
JSHint
ESLint
→
→
ESLint: белый список
module.exports = {
'rules': {
'space-before-function-paren': [2],
'no-shadow-restricted-names': [2],
'computed-property-spacing': [2],
'no-empty-character-class': [2],
'no-irregular-whitespace': [2],
'no-unexpected-multiline': [2],
'no-multiple-empty-lines': [2],
'no-constant-condition': [2],
…
ESLint: модульность
Исходный код
Парсер
Плагин 1
Список ошибок
Плагин 2
ESLint: автоисправление
if(foo) {
bar()}
if (foo) {
bar();
}
eslint --fix *.js
Самые популярные зависимости
- mocha
- chai
- lodash
- grunt
- gulp
- eslint
- babel-preset-es2015
- request
- async
- should
Линтеры CSS
Поддержка синтаксисов
SCSS
CSSLint
SCSS Lint
CSSComb
CSS
Less
Функции
Белый список
CSSLint
SCSS Lint
CSSComb
Модульность
Исправление
Количество правил
CSSLint
SCSS Lint
CSSComb
38
26
62
Stylelint
Исходный код
Парсер
Плагин 1
Список ошибок
Плагин 2
На что похожа модульность?
Единый фреймворк
Полифилы
Минификация
Линтинг
Примеси
Изоляция
Сменные парсеры
CSS
SCSS
Less
SugarSS
Битый CSS
Правило Stylelint — плагин PostCSS
const ruleName = "comment-no-empty"
(root, result) => {
root.walkComments(comment => {
if ( comment.text && comment.text.length === 0 ) {
report({ … })
}
}
}
Белый список правил
module.exports = {
'rules': {
'at-rule-name-case': 'lower',
'at-rule-semicolon-newline-after': 'always',
'block-closing-brace-newline-after': 'always',
'color-hex-case': 'lower',
'color-hex-length': 'short',
'color-hex-length': 'short',
'color-no-invalid-hex': true,
'indentation': 2,
…
Исправление
.foo {
color:black}
.foo {
color:black;
}
stylefmt *.css
postcss-browser-reporter
SCSS
CSSLint
SCSS Lint
CSSComb
CSS
Less
Stylelint
Белый список
CSSLint
SCSS Lint
CSSComb
Модульность
Исправление
Stylelint
CSSLint
SCSS Lint
CSSComb
38
26
62
Stylelint
168
Легко писать новые правила
Пользователи Stylelint
Популярность
Зачем линтить
Cеньор
Юниор
Код-ревью
Cеньор
Юниор
1. Меньше времени на код-ревью
Stylelint
«Я понимаю, что ты думаешь …, но …»
2. Критика роботов приятнее
3. Обмен практиками
module.exports = {
'extend': 'stylelint-config-wordpress'
}
4. Поиск ошибок
'color-no-invalid-hex',
'function-linear-gradient-no-nonstandard-direction',
'time-no-imperceptible',
'property-no-unknown',
'property-no-vendor-prefix',
'declaration-block-no-duplicate-properties',
'declaration-block-no-ignored-properties',
'declaration-block-no-shorthand-property-overrides',
'selector-class-pattern',
'selector-max-compound-selectors',
'selector-pseudo-element-no-unknown',
'selector-type-no-unknown',
'media-feature-no-missing-punctuation',
'no-unsupported-browser-features',
'no-unknown-animations',
'no-indistinguishable-colors',
'no-descending-specificity',
'no-browser-hacks'
#container .foo {
top: 10px;
}
…
.foo {
/* Expected selector .foo come before #container .foo */
top: 0;
}
.foo {
opacity: 1;
/* Features like this, which is unsupported in IE 8 */
}
.foo {
display: inline;
width: 100px;
/* Unexpected width with display: inline */
}
.foo {
margin-top: 10px;
margin: 0 auto;
/* Unexpected shorthand margin after margin-top */
}
.foo {
color: black;
}
…
.bar {
background: #010101;
/* Unexpected indistinguishable colors #010101 and black */
}
Как линтить
1. Линтер в текстовом редакторе
2. lint-staged — перед коммитом
"scripts": {
"lint-staged": "lint-staged",
},
"lint-staged": {
"*.css": "stylelint"
},
"pre-commit": ["lint-staged"]
3. Линтер в CI
4. Начните с популярного конфига
module.exports = {
'extend': 'stylelint-config-standard'
}
5. Добавляйте плагины
module.exports = {
'plugins': [
'stylelint-scss'
],
'rules': {
'scss/selector-no-redundant-nesting-selector': true
}
}
dustinspecker/awesome-eslint
6. Линтер — стайл-гайд
«В стайл-гайде не должно быть правил, которые нельзя описать в алгоритме»
7. Делайте исключения
.foo.is-started {
/* stylelint-disable no-unknown-animations */
/* Animation will be generated in JS*/
animation-name: js-generated-path;
}
.foo.is-started {
/* stylelint-disable no-unknown-animations */
animation-name: js-generated-path;
/* Expected comment reason after `stylelint-disable` comment */
}
8. Пишите свои правила
import { utils } from "stylelint"
export const ruleName = namespace("ИМЯ")
export const messages = utils.ruleMessages(ruleName, {
expected: "ТЕКСТ ОШИБКИ",
})
export default function () {
return (root, result) => {
/* ЛОГИКА */
}
}
Цвета повторяются — в переменные
colors = { }
return (root, result) => {
root.walkDecls(decl => {
decl.value.match(/#[0-9a-f]{3,6}/, color => {
if ( colors[color] ) {
utils.report({ … })
} else {
colors[color] = true
}
})
})
}
Правила Фейсбука
-
slow-css-properties
-
filters-with-svg-files
-
use-variables
-
mobile-flexbox
9. Два раза ошиблись — в правило
10. Линтите всё
gulp.task('default', ['lint',
'test',
'all-translated',
'spell-check',
'security-audit',
'file-size'])
postcss-sorting
div {
-moz-box-sizing: border-box;
width: 100%;
box-sizing: border-box;
position: absolute;
-webkit-box-sizing: border-box;
}
div {
position: absolute;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
}
yaspeller
$ yaspeller /home/ai/Dev/postcss/README.md
✗ /home/ai/Dev/postcss/README.md 453 ms
-----
Typos: 1
1. transorming (suggest: transforming, transporting)
-----
Node Security Platform
> nsp check
(+) 1 vulnerabilities found
┌───────────────┬───────────────────────────────────────────────────────┐
│ │ ReDoS via long string of semicolons │
├───────────────┼───────────────────────────────────────────────────────┤
│ Name │ tough-cookie │
├───────────────┼───────────────────────────────────────────────────────┤
│ Installed │ 2.2.2 │
├───────────────┼───────────────────────────────────────────────────────┤
│ Vulnerable │ >=0.9.7 <=2.2.2 │
├───────────────┼───────────────────────────────────────────────────────┤
│ Patched │ >=2.3.0 │
├───────────────┼───────────────────────────────────────────────────────┤
│ Path │ my-test-project@undefined > honeybadger@1.1.2 > requ… │
├───────────────┼───────────────────────────────────────────────────────┤
│ More Info │ https://nodesecurity.io/advisories/130 │
└───────────────┴───────────────────────────────────────────────────────┘
Ссылки
Stylelint — как и зачем линтить CSS
By Andrey Sitnik
Stylelint — как и зачем линтить CSS
- 9,703