Robots Must Suffer
linters and tools for front-end development
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4054143/2.jpg)
Andrey Sitnik
© Eric Joyner
Evil Martians
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4054198/article_robot.jpg)
I am from Russia
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4056102/a1.jpg)
Lead front-end developer at
Author of
Autoprefixer
PostCSS
Why did I create PostCSS
?
Two types of tasks
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059008/_pencilis_.256.1686.jpg)
Creative tasks
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
Boring tasks
Humans vs. robots
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059008/_pencilis_.256.1686.jpg)
Creative tasks
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
Boring tasks
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059025/XxjwnmE005008_20160128_BNMFN0A002_11n.jpg)
Humans
Robots
Robots don’t make mistakes
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
Work process
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
Talk
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
Analyze
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
Code
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
Test
Robots!
Talk
Analyze
Code
Test
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
Robots must suffer
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4054124/1.jpg)
© Eric Joyner
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059040/1.jpg)
© Eric Joyner
Part 2: What is linters?
Talk
Analyze
Code
Test
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
Test
- Lint
- Unit tests
- Integration tests
- Benchmarks
Talk
Analyze
Code
Test
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059009/More-Tuzki-Sticker-823256184360026.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
This talk is about linters
- Lint
- Unit tests
- Integration tests
- Benchmarks
What are linters?
Linters find mistakes in source code
Source code
Parser
Analysis
Errors list
Linting process
Unit tests vs. linters
y = 2 − (−x)
Unit tests
in: 2 out: 0
y(2) = 4, !== 0
Linters
−(−n) → +n
Unit tests vs. linters
Unit tests
Linters
Check input and output
Don’t find an error
Check source code
Tell exact line
Unit tests + linters =
"scripts": {
"test": "npm run lint && npm run unit-test"
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4060043/1.jpg)
Part 3
Popular
linters
© Eric Joyner
Node.js app
app.all('/apps/:user_id', request => {
initial = extract(request.body)
})
After 4 hours of debugging
app.all('/apps/:user_id', request => {
initial = extract(request.body)
})
app.all('/apps/:user_id', request => {
var initial = extract(request.body)
})
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4070186/f8cc8b84990148ec09a775bf69a90993--amazing-art-character-design.jpg)
var
Real story. Tests didn’t help.
ESLint could fix it
app.all('/apps/:user_id', request => {
initial = extract(request.body)
})
ESLint: initial is not defined app.js:2:3
The most popular dependencies
- mocha
- chai
-
eslint
- babel-preset-es2015
- lodash
JS linters evolution
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2873877/Pikachu.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2873882/42uDcM0siVA.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2873886/pichu.png)
JSLint
JSHint
ESLint
→
→
CSS
.foo {
margin-top: 20px;
width: 100px;
height: 100px;
}
Horizontal centering
.foo {
margin-top: 20px;
width: 100px;
height: 100px;
margin: 0 auto;
}
After 5 min of debugging
.foo {
margin-top: 20px;
width: 100px;
height: 100px;
margin: 0 auto;
}
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4070186/f8cc8b84990148ec09a775bf69a90993--amazing-art-character-design.jpg)
Stylelint could fix it
.foo {
margin-top: 20px;
width: 100px;
height: 100px;
margin: 0 auto;
}
Stylelint: this overrides the longhand property before it app.css:5:3
Stylelint languages
*.pcss
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4072666/logo.png)
*.scss
*.vue
postcss-scss
postcss-html
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4072680/less_logo.png)
*.less
postcss-less
Stylelint users
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2875320/16-logo.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4065799/a.jpg)
Part 4 Why
© Eric Joyner
Writing code vs. debug time
Dev
Debug
10 min
30 min
Normal
#1 Linters reduce debug time
Dev
Debug
10 min
30 min
Normal
10 min
25 min
With linters
Code reviews
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470369/tuzki_2013_avatar_21.jpg)
Senior
Junior
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2875903/97.png)
#2 Linters reduce code reviews
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470369/tuzki_2013_avatar_21.jpg)
Senior
Junior
Linter
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2471550/tuzki_2013_avatar_23.jpg)
It is hard to be a junior
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2471434/97.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470476/tuzki_2013_avatar_18.jpg)
Junior
Senior
Fixes
#3 Linters make juniors happy
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059021/811114_toys_512x512.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470361/tuzki_2013_avatar_07.jpg)
Junior
Linter
Fixes
Big companies → multiple teams
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059008/_pencilis_.256.1686.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470217/tuzki_2013_avatar_13.jpg)
Team 1
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4070186/f8cc8b84990148ec09a775bf69a90993--amazing-art-character-design.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4072047/tuzki_2013_avatar_01.jpg)
Team 2
Idea
?
#4 Sharing ideas
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4059008/_pencilis_.256.1686.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470217/tuzki_2013_avatar_13.jpg)
Team 1
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470361/tuzki_2013_avatar_07.jpg)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470217/tuzki_2013_avatar_13.jpg)
Team 2
Linter config
Idea
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4065802/a.jpg)
Part 5 How
© Eric Joyner
Step 1 Install linters via npm
npm install --save-dev eslint stylelint
Step 2 Create a config
.eslintrc
.stylelintrc
{
"rules": {
"no-console": "error"
}
}
Too many rules
ESLint: 300 rules
Stylelint: 161 rules
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470374/tuzki_2013_avatar_01.jpg)
Step 3 Extend shareable config
{
"extends": "standard",
"rules": {
"no-console": "error"
}
}
npm install --save-dev eslint-config-standard
Popular configs
ESLint
Stylelint
Step 4 Linter plugins for text editors
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2876350/68747470733a2f2f7261772e67697468756275736572636f6e74656e742e636f6d2f41746f6d4c696e7465722f6c696e7465722d7374796c656c696e742f6d61737465722f64656d6f2e706e67.png)
Linter plugins text editor
Sublime Text
VS Code
Too many errors?
ESLint: 250 errors in 100 files
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470476/tuzki_2013_avatar_18.jpg)
Step 5 Fix automatically
eslint --fix src/**/*.js stylelint --fix src/**/*.css
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2471224/tuzki_tact.png)
Other developers ignore linter
Good developer
Bad developer
git commit …
npm run test
npm run lint
git push …
git commit …
git push …
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4072623/mouse-pad-meme-like-a-boss.jpg)
Step 6 lint-staged
git commit …
run pre-commit hook
git add a.css
run stylelint a.css
Stylelint: 1 error
git: commit canceled
Install lint-staged
npm install --save-dev lint-staged pre-commit
lint-staged config
"scripts": {
"lint-staged": "lint-staged",
},
"lint-staged": {
"*.css": "stylelint"
},
"pre-commit": ["lint-staged"]
Step 6 Write custom plugins
Stylelint rule = simple PostCSS plugin
Facebook custom rules
-
slow-css-properties
-
filters-with-svg-files
-
use-variables
-
mobile-flexbox
Happened twice → write custom rule
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2470369/tuzki_2013_avatar_21.jpg)
Senior
Junior
Linter
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2471224/tuzki_tact.png)
Custom rule
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4072696/pile-of-poo_1f4a9.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4072696/pile-of-poo_1f4a9.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4072696/pile-of-poo_1f4a9.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4065837/a.jpg)
Part 6
Other linters
© Eric Joyner
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/2948385/ZjkRdsi.png)
The best ESLint plugins
My favorite ESLint plugins
-
eslint-config-import
-
eslint-plugin-security
-
eslint-plugin-node
The best Stylelint plugins
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4085427/5BoKJXD.png)
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%;
}
Sort CSS properties
Lint English
$ yaspeller /home/ai/Dev/postcss/README.md
✗ /home/ai/Dev/postcss/README.md 453 ms
-----
Typos: 1
1. transorming (suggest: transforming, transporting)
-----
Check security in Node.js dependencies
> 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 │
└───────────────┴───────────────────────────────────────────────────────┘
Check webpack bundle size
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4072758/example.png)
Check accessibility
pa11y --config ./path/to/config.json http://example.com
![](https://s3.amazonaws.com/media-p.slid.es/uploads/467124/images/4065841/b.jpg)
The end
© Eric Joyner
Links
@andreysitnik VPN☺
@evilmartians VPN☺