Reactのプロジェクトを平成最後の大リファクタリングした話
平成の技術的負債を令和に持ち越したくないからリファクタリングしよう!!と思ったのが事の始まりでした。
短期的に開発速度を求めLintを後回しにしてしまったプロジェクトにLintツールを導入し、Reactのコードを全て綺麗にした時のツールや方法を書きます。
Lintとは
ソースコードを静的にチェックし、書式やバグの原因になるような曖昧な記述について警告してくれるプログラムの事です。
Lintツールを使うと実行時エラーなどとは違ってコードを実行する前に警告を確認できるため、常に綺麗な状態を保つことができます。
やりたいこと
前提としてプロジェクトはReact+Reduxで、ECMAScriptで記述されています。
- コード整形
- 構文チェック
- コミット時の自動Lint
- プロジェクト全体の警告状況を可視化(Lintエラー数などがグラフで見れると嬉しい)
導入したツール
JavaScriptコードのLintが必要なのでどんなツールがいいのか色々調べました。
するとESLint
とPrettier
という2つのツールがよく使われているようです。
ESLintはコード整形はもちろん他にも多くのチェック機能が付いています。そしてPrettierはコード整形に特化したツールです。 ESLintだけで事足りそうですがPrettierを併用する理由としては、Prettierの方がコード整形が上質で、しかも簡単に設定・実行できるからです。
という訳で、ESLintとPrettier、そしてそれらを併用するための周辺ライブラリを導入します。
- prettier
- 整形ツール
- eslint
- 整形ツールを含めたLintツール
- eslint-config-prettier
- ESLintとPrettierを繋ぐライブラリ
- eslint-plugin-prettier
- ESLintとPrettierを繋ぐライブラリ
- eslint-plugin-react
- ESLintでReactのコードを検査するためのライブラリ
- eslint-nibble
- Lintエラー数や種類をグラフで可視化できるツール(通常はなくても困らない)
$ npm install --save-dev prettier eslint eslint-config-prettier eslint-nibble eslint-plugin-prettier eslint-plugin-react
次にコミット時に自動Lintできるように追加のライブラリを導入します。
- husky
- Gitのcommitやpushに対して処理をhookするライブラリ
- lint-staged
- Gitにステージングされたファイルに対してLinterを実行するライブラリ
$ npm install --save-dev husky lint-staged
これでとりあえず必要なライブラリは全て導入しました。 あとはやるだけですね。
※ESLintやPrettierの設定を見たい方はこちらをご覧ください。
現状確認
まずは現状を把握するために入れた可視化ツールを使ってみましょう。
プロジェクトのルートでnpx eslint-nibble ./
を実行します。
ぴったり400個ものエラーがありますね。おぞましい数です......。
さすがにこれを一気に修正するには規模が大きすぎて脳のリソース的にも、影響範囲的にも難しそうです。 少しずつ修正を加えていきましょう。
解決
基本的にはLintツールを走らせれば、整形だけで対応できるコードは自動的に修正してもらうことができます。
$ npx eslint file.js --fix
このコマンドを実行すれば指定したファイルにLintを実行し、発生したコード書式の問題などは自動で修正しファイルを上書きしてくれます。
しかし、コード書式だけならこれで問題ないのですが自動で修正できないLintエラーも存在します。
ReactのコンポーネントにはpropTypes
という、引数のようなものに型を指定する方法が存在します。
この型指定はしてもしなくても実行に差し支えはありませんが、指定した方がコードのバグチェックなどにも役立つため書くことを推奨されています。
これらはLintツールが自動で修正することはできませんので、自分で該当箇所を見て型を追加する必要があります。
その他には、使っていない変数やimportされた物がある場合もエラーが発生しますが、自動修正はされません。
であればコード整形の他に、忘れられた変数たちや型の定義を自分でしていく必要がある訳ですが、広範囲に渡る修正のためどこから手をつけていくか考える必要がありそうです。
そんな時はまずeslintコマンドに--fix
オプションを付けずに実行してみましょう。
そうすれば、Lintエラーの一覧だけが表示され修正の上書きはされません。
$ npx eslint file.js
エラーの内容を見ていくと、書式系のエラーと自動修正できなさそうなエラーがある程度わかります。 まず影響範囲の少ないファイルやディレクトリから順番にチェックしながらエラーを修正していきます。
私の場合は小さなコンポーネントディレクトリから順番に攻めました。 ディレクトリ以下を一括でチェックする場合は以下のようにすれば良いです。
$ npx eslint AComponent/*/*
ここでいきなりfixを付けるよりかは、一旦エラーの数や度合いをチェックした方が良いです。 もし自動修正できないエラーの数が多いようであれば、チェックする領域を狭めながら一度に修正しやすい範囲に押さえましょう。 そうでないと1コミットの修正量が異常な数になったり、同時に直す箇所が多すぎて手が回らなくなったりする可能性があります。
一度に修正する範囲が決まったらその範囲だけを--fix
オプションを付けたeslintコマンドで自動修正しましょう。
その後、残ったエラーを手動で解決していくと良いです。
$ npx eslint AComponent/*/* --fix
一度に修正すると決めた範囲の修正が終わるごとにコミットしましょう。 毎回コミットをせずにまとめてやってしまうと、コードレビューの時にレビューの手が回らなくなってしまいます。 修正する時に手が回らない範囲をコミットしてしまうと、コードレビューの手が回るわけがありませんから。
コミットと同時にプルリクエストの規模が大きくなりすぎるのも問題です。 流石に1コミットごとにプルリクエストを出すわけではありませんが、1~200行程度、多くとも1000行以下で一度プルリクエストを出して欲しいです。 こちらもコードレビューがひたすら辛くなってしまいますし、一度の影響範囲が大きくなりすぎて他の作業者と競合してしまう可能性が高くなってしまいます。
後はこれらのことを気をつけて地道に修正していけばその先に待つのはなんのLintエラーも無い、すっきりとした開放的な環境です。
修正完了
Lintエラーを全て解消しました!!
最後に、これからはLintエラーを含んだコードをリポジトリに混入させないよう、コミットにhookしてLintエラーを自動修正・エラー出力・問題がある場合にコミットを取り消しするように設定します。
package.json
に設定を追記しましょう。
"scripts": { "precommit": "lint-staged" }, "lint-staged": { "*.{js,jsx}": [ "eslint ./ --fix", "git add" ] },
これでLintエラーを含んだままコミットしようとしてもリポジトリが汚されることはありません!
ああ、なんと素晴らしいことでしょうか......。
まとめ
このプロジェクトの規模はjs・jsxファイルを合わせて70ファイルで5000行程度でした。 この程度のプロジェクトでも1.5人日(約12時間)程度かかりました。
おそらく業務コードや長期間運用するコードはこれどころではない規模になってしまうと思います。 Lintツールを導入するのにはそこまで時間がかかりませんし、最初から導入していれば後から面倒な修正作業も発生せず、常に綺麗なコードを保つことができます。
迷ったらとりあえずLintツールをいれましょう。
さもなくば後から発狂することになりますよ......。