prettierの使い方

ということで、JavaScriptのフォーマッタの[prettier](https://github.com/prettier/prettier)の紹介です。
React Confで紹介されてたものを色々試してみようと思って、まずはprettierを試してみました。

# 追記

* 2017/4/14: [Prettier1.0](http://jlongster.com/prettier-1.0)(とMinor fixあてた1.1.0)が出ました。本記事の内容は1.0でもそのまま問題なく適用できました。
* 2019/7/7: prettier-eslintよりも[eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier)を使ったほうが良さそうです

# prettierとは

* JavaScriptのコードを整形してくれるフォーマッタ。他言語で言うとGolangのgofmtみたいなもの。
* 他のフォーマッタと比べて設定項目が少ないので開発者間で迷いなく共通のスタイルで統一される。
* まだベータ。
* 1月にリリースされてから2ヶ月ちょっとでスター数6000超え。例えばeslintは3年以上前のリリースで7000ちょっとなので、かなり成長早いと思われる。([star history](http://www.timqian.com/star-history/#prettier/prettier&eslint/eslint))
* ES2017、JSX、Flowとかもサポートされてる。
* React本体にも[このPR](https://github.com/facebook/react/pull/9101)で適用された。
* もちろんReact関係なく、普通のJavaScriptにも適用できる。(このポストにもReactは全く出てきません)
* eslintとの連携も可能。
* 色々なエディタ/IDEでサポートされてる。
* コードをもっとぷりてぃにしよう、みたいなおやぢギャグが言いたくなる。

# 使い方

## 単体で使う

とりあえずプロジェクトを初期化してprettierを入れてみます。

```bash
yarn init
yarn add -D prettier
```

次に適当にJavaScriptのファイルを作ります。

```javascript:index.js
'use strict'

var foo = {
  bar: 'bar string',
  baz: 11
}

console.log(foo);
```

prettierしてみます。

```bash
$ prettier index.js
"use strict";

var foo = {
  bar: "bar string",
  baz: 11
};

console.log(foo);
```

コードが整形されました。

--writeを付けるとファイルを上書きします。

```bash
$ prettier --write index.js
index.js 63ms
```

## eslintと合わせて使う。
(2019/7/7追記)
[このissue](https://github.com/prettier/prettier-eslint/issues/206)と[この質問への回答](https://stackoverflow.com/a/44690309/1390607)を見る限り、現在はprettier-eslintよりもeslint-plugin-prettierが推奨のようです。
(追記ここまで)

既存のプロジェクトだと既にeslintが入っててprettierが整形する結果とconflictすることがあると思います。そんな場合はprettierのオフィシャルアカウントが提供している[prettier-eslint](https://github.com/prettier/prettier-eslint)を使うことでprettierで整形した結果を`eslint --fix`に渡すことができるようになります。


コマンドラインから実行する場合には[prettier-eslint-cli](https://github.com/prettier/prettier-eslint-cli)も必要になります。

ということで、それぞれインストールしていきます。

```bash
yarn add -D eslint prettier-eslint prettier-eslint-cli
```

`eslint --init`はyarnに対応してないので、手動で設定ファイルを作ります。
eslintの設定ファイルはjson、yml、JavaScriptで書けますが、[React本体に倣って](https://github.com/facebook/react/blob/master/.eslintrc.js)JavaScriptで書きます。

今回は簡単にprettierのデフォルトとconflictする設定を確認するために、クォートをシングルにする設定だけ入れてみました。

```javascript:.eslintrc.js
'use strict';

const ERROR = 2;

module.exports = {
  rules: {
    'quotes': [ERROR, 'single']
  }
};
```

そしてprettier-eslintを実行してみます。

```bash
$ prettier-eslint index.js
'use strict';

var foo = {
  bar: 'bar string',
  baz: 11,
};

console.log(foo);

success formatting 1 file with prettier-eslint
```

これも--writeオプションを付けると上書きできます。

```bash
$ prettier-eslint --write index.js
success formatting 1 file with prettier-eslint
```

## precommitフックを使う

gitのレポジトリには整形後のものだけを残しておきたいと思います。そんなときはprecommitフックでprettierを実行して整形したものをコミットするようにします。
prettierのREADMEにある[husky](https://github.com/typicode/husky)と[lint-staged](https://github.com/okonet/lint-staged)を使えば、prettier-eslintの場合でも同じように実現できます。

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

そして`package.json`に以下を追記します。(ちなみにgitのルートディレクトリから見てサブディレクトリにpackage.jsonがある場合は少し設定が変わります)

```json
  "scripts": {
    "precommit": "lint-staged"
  },
  "lint-staged": {
    "*.js": [
      "prettier-eslint --write",
      "eslint", // これを入れないとエラーがあってもコミットされてしまう
      "git add"
    ]
  },
```

試しにindex.jsを以下のようにダブルクォートかつ末尾のセミコロン無しなものに書き換えます。

```javascript:index.js
"use strict"

var foo = {
  bar: "bar string",
  baz: 11,
}

console.log(foo)
```

commitテスト用に同じ内容のファイル`foo.js`を作ります。

```bash
cp index.js foo.js
```

そしてindex.jsのみコミットします。

```bash
git add index.js
git commit -m 'added index.js'
```

するとprecommitに書いた処理が走って整形されたコードがコミットされます。


addしたindex.jsのみが整形された上でコミットされてます。(foo.jsは整形もコミットもされない)

```bash
$ git show --pretty="" --name-only  f83bc9b5a12f8a713
prettier/index.js

```

## エディタ連携

[prettierのREADME](https://github.com/prettier/prettier#atom)には様々なエディタ/IDEで対応されているように書かれています。でも[prettier-eslint-cliのREADME](https://github.com/prettier/prettier-eslint-cli#vim)にはVimのみ書かれているので、今回はvim連携を試します。

READMEには`autocmd BufWritePre *.js :normal gggqG`でプラグイン無しでも保存時に自動整形できるよみたいな男らしいことが書かれていますが、カーソル位置が保存されないので、[このissue](https://github.com/prettier/prettier/issues/658)にあるように[neoformat](https://github.com/sbdchd/neoformat)を使うと良いんじゃないかと思います。

設定はこんな感じです。インストール自体はdeinとかで適宜入れてください。

```vim
let g:neoformat_javascript_prettiereslint = {
      \ 'exe': './node_modules/.bin/prettier-eslint',
      \ 'args': ['--stdin'],
      \ 'stdin': 1,
      \ }
augroup fmt
  autocmd!
  autocmd BufWritePre * Neoformat
augroup END
let g:neoformat_enabled_javascript = ['prettiereslint']
```

# 最後に

今回試したものは[ここ](https://github.com/daikikohara/learning-from-reactconf2017/tree/master/prettier)に置いてます。参考になれば幸いです。でもちょっとだけ設定変えちゃいました(てか、シングルクォートとダブルに戻したので紛らわしいかもです)。