こんにちは! アメーバブログでフロントエンド開発をしている2017年新卒エンジニアの上西です。
今回は、昨年度の刷新でReact + Reduxの構成になったアメブロのフロントエンドにESLint + Prettierで自動コード整形を導入した話をしたいと思います!
ESLintとは / Prettierとは
ESLintはJavaScriptのLinterです。 スタイルガイドラインに準拠していない問題のあるパターンやコードを見つけることができ、軽微なエラーならAutoFixできます。 アメブロでは刷新当初から導入していましたが、AutoFix機能を利用していなかったため軽微なLintエラーでも手動で直す必要がありました。
Prettierはコードフォーマッターです。 コマンド1発でコードを一貫したスタイルに自動整形できます。 ES2017やJSX、Flow、CSSなどの様々な言語に対応していて、さらに対応に向けて開発が進行中の言語も多数あります。 アメブロではこれまで導入していませんでした。
併用するのはなぜ?
ESLintとPrettierはどちらもコード整形を行えるため一部役割が被っています。 しかし、ESLintはバグの原因になりやすいパターンなどコード品質に関するチェックも行える一方で、コード整形を自動で行うことに関してはPrettierの方が強力です(Prettierの作者の記事を参照)。 そのためESLintとPrettierは併用することが一般的になっています。
今回アメブロではESLintのAutoFix機能の利用とPrettierの導入を一気に行うことにしました。
併用方法
併用方法はPrettierのドキュメントが参考になります。 ここで紹介されている方法の1つは、ESLintの実行時にPrettierを呼び出すようにするeslint-plugin-prettierというESLintのプラグインを導入する方法です。 この方法はすでにESLintを利用していたアメブロにとって最適な方法です。
他の方法として、先にPrettierで整形し、その結果をESLintに渡すことで両方の処理を適用するprettier-eslintというツールを導入する方法もあります。
しかし、prettier-eslintはどこが変更されるか実行してみるまでわからないのに対して、eslint-plugin-prettierならESLintの普通のチェック(AutoFixなし)を行うだけでPrettierを含む変更対象をLintエラーとして確認できます。 また、エディタプラグインなども普通のESLint用のプラグインでいいので、すでにESLintを利用していたアメブロではeslint-plugin-prettierを導入することにしました。
また、Prettierが提供しているeslint-config-prettierというツールも導入しました。 前述の通りESLintとPrettierの役割が一部被っているため、両者のルールが衝突しないようにする必要があります。 このツールはESLintのルールのうちコード整形関連のルールを無効化して衝突を回避します。
これらによって、Prettierの強力な自動コード整形と、ESLintのコード品質関連のチェックの両方の恩恵を受けられます。
アメブロでの導入方針
CSS
ここまでの説明はPrettierをJavaScriptに適用する場合の話でした。 しかし、PrettierはCSSにも対応しています。 当然アメブロでも、CSSにも適用することを検討しました。
アメブロではすでにCSSのLinterであるstylelintを導入しています。 stylelintのREADMEを確認してみると、残念ながらAutoFixは実験的機能とされていて、いくつか解決すべき問題があるようでした。 できればeslint-plugin-prettierのようにstylelintからPrettierを呼び出したいと考えていたので、とりあえず今回は導入を見送ることにしました。
pre-commit
先日のFrontrend Vol.11で筆者が登壇させていただいた際、Prettier導入についても少しだけ触れたのですが、ありがたいことに後にTwitterで次のような質問を拝見しました。
pre-commit ではないの何か理由があるのかな #frontrend
— オートミール (@Sakunyo) 2018年3月9日
pre-commitとは、Gitにおいて、コミット直前にコミット対象のコード断片に対してスクリプトを実行できる、Gitフックの1つです。 これを利用すればコミット時にコードを検査したり自動整形したりできます。
Prettierを導入するときにpre-commitツールを利用する事例は多く、Prettierのドキュメントでも紹介されています。 アメブロでも導入は検討したのですが、結論からいうと今回はとりあえず見送りました。
この判断に至った決定的な理由はないのですが、挙げるとすると以下の2つがあります。
- 変換結果を目視確認できるタイミングで実行したかった
- pre-commitツールのlint-stagedが
git add -p
に未対応だった(Issue #62 · okonet/lint-staged)
特に前者は、導入作業中に意図しない箇所で改行される現象を何度か目撃したことから不安視するようになりました。 以下の例ではESLintのエラーになるので気付くのですが、普通のコメントでこうした現象が起きると目視しない限り気付けません。
// Input
for (const id in obj) { // eslint-disable-line
console.log(id)
}
// Output
for (const id in obj) {
// eslint-disable-line
console.log(id);
}
※ちなみにPrettierでは eslint-disable-line
の代わりに eslint-disable-next-line
を使うように説明されていますが(Issue #3011 · prettier/prettier)、アメブロではそもそもdisableコメントの利用を推奨していません。
今回は実行の手間を省く方法として、エディタ保存時にESLintのAutoFixを実行するエディタプラグインなどを利用するように勧めていくことにしました。
また、pre-commitで自動修正までしてしまわずに普通にLinterでチェックするだけなら便利かもしれないので、とりあえず今回は全て見送りましたが要望があれば対応するつもりです。
導入手順
インストール
アメブロではESLintは導入済みだったので、以下のパッケージをインストールしました。
yarn add --dev prettier eslint-plugin-prettier eslint-config-prettier
設定
.eslintrc.jsonに設定した主な項目は以下の通りです。
{
"extends": [
...
"plugin:prettier/recommended",
"prettier/react"
],
...
}
ちなみに "plugin:prettier/recommended"
はeslint-plugin-prettierによるもので、以下の3つの設定を追加してくれます(eslint-plugin-prettierのREADMEを参照)。 全部自分で設定しても同じです。
{
"extends": [
...
"prettier"
],
"plugins": [
...
"prettier"
],
"rules": {
...
"prettier/prettier": "error"
}
...
}
新規作成した.prettierrc.jsonは以下のように設定して、これまでのESLintのルールと同じようなルールで整形されるようにしました。 その他はデフォルト設定のままです。
{
"singleQuote": true,
"trailingComma": "all"
}
package.jsonには以下のようなスクリプトを設定しました。 これで yarn fix
コマンドが使えるようになります。
{
"scripts": {
"fix": "run-s fix:js",
"fix:js": "eslint . --quiet --fix",
...
},
...
}
既存コードに適用 / 修正
yarn fix
コマンドでPrettierを既存コードに適用し、さらに一部は手動で修正しました。
手動修正は前述の通り勝手に改行されて無効になってしまった eslint-disable-line
を eslint-disable-next-line
に書き換えるなどした他、無用となった eslint-disable-line max-len
などを削除しました。
告知後マージ
今回はmax-lenに関してPrettierのデフォルト設定(80文字)を利用するようにしたこともあって、初回適用で既存コードに対する変更が大量に発生しました。
そのため他の開発者の変更が高確率でコンフリクトすることが考えられたので、Slackで事前に告知して注意を促しました。 また、コンフリクト解消の手順についても、Prettier適用のコミットとPrettier適用直前のコミットで分けてリベースすることと、Prettier適用のコミットでリベースするときは雑に解消していい(再度Prettierを適用し直すだけでいい)ことを伝えました。
まとめ
これまでのアメブロではPrettierはもちろんESLintのAutoFix機能も利用していなかったため軽微なLintエラーでも手動で直す必要がありました。 そのためCIテストを通すのも一苦労で、以前のスライド(p.91)では「Lintスパルタ」という言葉で表現されていました。
それが今回ESLintのAutoFix機能とPrettierを導入したことで、コードフォーマットや軽微なLintエラーは自動で修正できるようになりました。 この自動修正は yarn fix
コマンドを打ってもいいですし、開発者が各自エディタにプラグインを入れれば保存する度に自動で実行させることができます。
この改善のおかげで、開発時にコードフォーマットなどについて考える必要がなくなり、スピード感を保って開発できるようになりました。 また、CIテストもすぐに通るようになったのでテンポよく開発できるようになりました。
昨年度に刷新したアメブロのフロントエンドですが、それでもまだ課題は残っています。 少しずつではありますが、歴史ある巨大システムを守るためにこれからも継続して改善を進めていきます!