PrettierとLinterを併用する

![ALE_stylelint-fix.gif](https://qiita-image-store.s3.amazonaws.com/0/100988/36bb6cb4-6730-c470-815c-36403f904221.gif)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com)

## TL;DR

Prettier触ってみたかったので、boilerplateっぽいのを[作った](https://github.com/sigwyg/Linting-and-Formatter_boilerplate)。

- JSはESLint。CSSはStylelintを使います。
- FormatterとしてPrettierを使用。これはJSのみ。
- `git commit`時に自動整形されるようにしておく。

PrettierそのものはCSSにも対応しているが、Stylelintと併用しようとすると、まだ足りない感じなので様子見。けっきょくPrettierしてるのはJSだけなので、なんだか片手落ちな感が否めない。追って対応していきたいところ。いちおレガシーCSSに導入するときとか事前にPrettier通しておくと、多少は楽だった。

コーディングルールに関しては一例として、今回は無難なルールをベースに設定しています。

- [eslint-config-standard](https://github.com/standard/eslint-config-standard)
- [stylelint-config-standard](https://github.com/stylelint/stylelint-config-standard)

導入数でいえばGitHubやAirBnBコーディングルールが多数派だが、Linter導入の目的としてはstandardの方が合っているだろうと思う。

## メリット

- 記法が統一されるとレビューで見やすくなる
- 細かいコードの書き方で揉めるのを防ぐ
- 並び順とか手動でやらせると非現実的な指定を、自動で行える

> Q. PrettierとLinterの--fixオプションは何が違うの？

A. Prettierはコードの整形はするが、警告を出してくれない。
コードの整形そのものは、LinterよりPrettierのほうが巧くやってくれる(1行80文字とか)。とはいえ、あまり細かな指定はできない。なんなら.editorconfigのほうが多いかもくらいなので。

Linterが出してくれる警告には意味があるので消したくないが、エラーがindentで埋まるのは好ましくないので使い分ける。Linterには「記法の統一」と「品質の担保」という2つの側面があって、前者を機械的に処理することによって、本質的なレビューに専心できる。

参考: [Prettier vs. Linters](https://prettier.io/docs/en/comparison.html)

## デメリット

- エディタ連携すると好みのスタイルで書けない
- Pre-commit設定するとコミット時に多少もたつく

手元では好きなスタイルで書かせておいて、push時にインデントとか整形するってのが、一番Prettierを活かしてるスタイルな気がする。`eslint-plugin-standard`を抜けばできそうに思うが、どうせmergeすれば変わってるので良いかなとシンプルに`--fix`で纏めることにした。

## Install

```
$ yarn add -D prettier
$ yarn add -D eslint eslint-plugin-prettier eslint-config-prettier
$ yarn add -D eslint-config-standard eslint-plugin-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node
$ yarn add -D stylelint stylelint-order stylelint-config-standard
```

## Usage

```
$ eslint --fix src/**/*.js
$ stylelint  --fix src/**/*.css
```

ESLintがPrettierを実行するように設定しているのでシンプル。エラーもPrettierの出力を前提にチェックしている。sylelintはそのままで、Prettierなし。

## Pre-commit Hook

全員にエディタプラグイン入れさせるのは現実的でないため、
`git commit`すると自動でLinter/formatterが走るように設定しておく。

```
$ yarn add -D lint-staged husky
```

```package.json
  ...
  "scripts": {
    "precommit": "lint-staged"
  },
  "lint-staged": {
    "src/**/*.{js,json}": [
        "eslint --fix", "git add"
    ],
    "src/**/*.{css,scss}": [
        "stylelint --fix", "git add"
    ]
  },
  ...
```

参考: [Pre-commit Hook](https://prettier.io/docs/en/precommit.html)

## Note: ESLintと併用する場合

PrettierとESLintと併用する場合、2つの方法がある

1. `eslint-plugin-prettier` 
    - ESLintのworkflowで処理する
    - Prettierの出力が維持される
    - .eslintrcにprettierが明記されるので判りやすい
    - `eslint-config-prettier` を使えば、ESLintのPrettierと重複してるルールを無効化してくれる
    - `eslint --fix` だけで、PrettierとESLintの自動修正を同時に行ってくれる
    - [Integrating with ESLint](https://prettier.io/docs/en/eslint.html)
2. `prettier-eslint`
    - Prettierしてから`eslint --fix`に渡す
    - Prettierのオプションは`.prettierrc`で管理する
    - `prettier-eslint --write`で`eslint --fix`もしてる

ESLintがPrettierを実行するか、PrettierがESLintに渡すか。
ほとんど変わらないが、後者だと`--fix`なしでチェックだけしたいってのができない。あと、`prettier-eslint` の作者は[もう使ってない](https://twitter.com/kentcdodds/status/913760103118991361)とのことなので、現実的には`eslint-plugin-prettier`一択。

## Note: CSSの場合

`stylelint --fix`を用いて整形まで行う。

[stylelint-order](https://github.com/hudochenkov/stylelint-order)を入れれば、プロパティのソートが可能になる。postcss-orderの内部で使われていて、今回の場合は`stylelint-idiomatic-order`に含まれている。

少し前ならstylefmtて良いツールがあって、Prettierのissueからも誘導されてたけど、stylelintが`--fix`に対応したので開発が止まってる。prettier使うか、`stylelint --fix`しろって感じらしい。

- [Stylistic issues](https://stylelint.io/VISION/#stylistic-issues)
- [Prettier + Stylelint: Writing Very Clean CSS (Or, Keeping Clean Code is a Two-Tool Game)](https://css-tricks.com/prettier-stylelint-writing-clean-css-keeping-clean-code-two-tool-game/)
- [Prettier for CSS](https://github.com/stylelint/stylelint/issues/2532)

## Note: prettier-stylelint(できなかったメモ)

```
$ yarn add -D stylelint prettier-stylelint
$ yarn add -D stylelint-config-standard stylelint-config-idiomatic-order
$ yarn add -D stylefmt
$ prettier-stylelint --write src/test.css
```

prettier-eslintから着想を得たらしい、prettier-stylelintがあるが、2018-03-30時点ではCLIでは整形されるものの、エラー終了しているのでVimプラグインでは変化しなかった。おそらく以下のエラーを吐いているから。

```
`{ "parser": "postcss" }` is deprecated. Prettier now treats it as `{ "parser": "css" }`.
```

- [Warning: `parser` with value "postcss" is deprecated. Use "css", "less" or "scss" instead.](https://github.com/hugomrdias/prettier-stylelint/issues/3)
- [Cannot set property 'singleQuote' of null](https://github.com/hugomrdias/prettier-stylelint/issues/9)


## Vim Setup

公式でいくつかのエディタに対応している旨が紹介されている。
[Editor Integration](https://prettier.io/docs/en/editors.html)

以下はVimの場合。

### ALE

非同期でチェックが走るので、Syntasticなんかより軽い。設定項目が少なく、標準で多くの言語とツールに対応している。AirLineに対応している点もポイント高い。

```dein.toml
[[plugins]]
repo = 'w0rp/ale'
hook_add = '''
    let g:ale_fixers = {
    \    'javascript': ['prettier-eslint'],
    \    'css': ['stylelint'],
    \    'scss': ['stylelint'],
    \}

    " if you want to fix files automatically on save.
    let g:ale_fix_on_save = 1
'''
```

### Neoformat

シンプルで良さそうだったが、標準で`stylelint --fix`に対応しておらず、標準出力の受け渡しまわりが巧くできなかった。ひとまず例として紹介しておく。

```dein.toml
[[plugins]]
repo = 'sbdchd/neoformat.git'
hook_add = '''
    "let g:neoformat_verbose = 1 " only affects the verbosity of Neoformat

    " Enable tab to spaces conversion
    let g:neoformat_basic_format_retab = 1

    " Enable trimmming of trailing whitespace
    let g:neoformat_basic_format_trim = 1

    " js
    let g:neoformat_javascript_prettiereslint = {
        \ 'exe': './node_modules/.bin/prettier-eslint',
        \ 'args': ['--stdin'],
        \ 'stdin': 1,
        \ }
    let g:neoformat_enabled_javascript = ['prettiereslint']

    " css
    let g:neoformat_css_stylelint = {
        \ 'exe': './node_modules/.bin/stylelint',
        \ 'args': ['--stdin', '--fix'],
        \ 'stdin': 1,
        \ }
    let g:neoformat_enabled_css = ['stylelint']

    augroup fmt
        autocmd!
        autocmd BufWritePre *.js Neoformat
        autocmd BufWritePre *.css Neoformat
        autocmd BufWritePre *.scss Neoformat
    augroup END
```

## 参考

- [Related Projects - Prettier](https://prettier.io/docs/en/related-projects.html#eslint-integrations)
- [アメブロに ESLint + Prettier で自動コード整形を導入した話](https://developers.cyberagent.co.jp/blog/archives/15068/)
- [ESLint(あるいはTSLint)とPrettierを併用する](http://tech-1natsu.hatenablog.com/entry/2018/01/07/154941)
- [GitHubに置いた作例](https://github.com/sigwyg/Linting-and-Formatter_boilerplate)