この記事は GiXo アドベントカレンダー の 2 日目の記事です。
昨日は、「GiXo Advent Calendar 2021」でした。
Data-Informed 事業本部 / Technology Div. の濱田です。
React + Typescript プロジェクトにおける、時間対効果が高いコードチェック構成について、弊社の事例を交えてご紹介させていただきます。
はじめに
コードの品質を保つために ESLint
に代表される linter や Prettier
に代表される formatter などのコードチェック機能が存在します。便利ですが、プロジェクトが大きくなってくると実行時間の長さがネックになってきます。
そこで、効率よくコードチェックを行うためにはどうすれば良いのか、弊社の例をご紹介させていただきます。なお、本内容はプロジェクトの規模や成熟度、GitHub 運用方針や lint ルールの設定・・・など環境に依存するところが大きいと考えています。あくまで一例として捉えていただけますと幸いです。
結論
結論から書きますと、Before / After は下記のとおりです。
Before
- pre-commit
- eslint(ステージングファイルのみ)
- prettier(ステージングファイルのみ)
- GitHub Actions
- eslint
- prettier
- TypeScript 型チェック
After
- pre-commit
- prettier(ステージングファイルのみ)
- pre-push
- eslint
- TypeScript 型チェック
- GitHub Actions
- eslint
- prettier
- TypeScript 型チェック
Before について
pre-commit
時にステージングファイルを対象に eslint
および prettier
を実行します[1]。
GitHub Actions では全体[2]を対象に eslint
および prettier
を実行し、加えて TypeScript の型チェックを行います。
pre-commit
時の動作については、例えば freeCodeCamp でも同様の設定が行われており[3]、比較的オーソドックスな内容かと思われます。ただし、今回対象となったプロジェクトでは下記のような点がネックとなっていました。
- GitHub Actions で TypeScript の型チェックに引っかかり手戻りが発生する
eslint
の実行に時間がかかる
1 については、GitHub Actions で手戻りが発生すると時間ロスが大きいため、解消したいところです。
2 については、プラグインの状況など設定ファイルに依存するところもありますが、少なくとも 4s 以上の時間がかかっていました。塵も積もれば山となるので、コミットの都度 4s が発生するのは避けたいところです。
After について
pre-commit
時にステージングファイルを対象に prettier
を実行します。pre-push
時に全ファイルを対象に eslint
および TypeScript の型チェックを実行します。
設定内容としては下記のようになります。
1 2 3 4 5 6 |
#.husky/pre-commit #!/bin/sh . "$(dirname "$0")/_/husky.sh" yarn pretty-quick --staged |
1 2 3 4 5 6 7 |
#.husky/pre-push #!/bin/sh . "$(dirname "$0")/_/husky.sh" yarn eslint --fix --max-warnings=0 . yarn tsc -p . --noEmit |
pre-commit
時に prettier
を行うことで、コード整形を行います。こちらは遅くとも 1s 以内に完結するので、ストレスになくコミットできます。eslint
や TypeScript の型チェックといった時間がかかる処理については、pre-push
のタイミングでまとめて行います。こちらで設定を行うことで、GitHub Actions で手戻りが発生することを避けられます。
最後に GitHub Actions で相変わらず全てチェックを行なっていますが、下記の理由からそのようになっています。
- GitHub Actions で Firebase Hosting のプレビューチャネルへのデプロイなどコードチェック以上に時間がかかる処理を行なっているため、ボトルネックにならない
- git commit –no-verify などオプションで事前のチェックを無視できてしまうので、念のため
その他の検討事項
- Deno の導入
Deno は 「Javascript / TypeScript 向けの、Rust で書かれたシンプルでモダンでセキュアなランタイム」[4]です。「eslint
が遅いならdeno lint
を使えば解決されるのでは?」というのは確かにその通りで・・・実際に試したところ、一瞬にして lint が完了しました。これは素晴らしいということで最初は記事のタイトルを「Deno で高速な linter と formetter を手に入れる」にしようと思っていたのですが、今回対象となったプロジェクトではeslint
の設定ファイルをカスタマイズして使っていました。このあたりで折り合いがつかなかったため、deno lint
に乗り換えることに懸念があり、導入を見送りました。
ちなみに、Deno で利用可能な lint ルールは下記の通りです。
https://lint.deno.land/
Deno は linter や formatter のルールは統一されているべきだ、という立ち位置です[5]。いまなお開発が行われていますが、今後もカスタマイズを推奨するような更新が積極的に行われることはないと考えています。一方でルールは一通り揃っており、ON/OFF を切り替えることができます。プロジェクトの状況によっては導入する価値が十分にあるかと思います。
pre-push
時に検査するファイルを絞り込む
例えばこちらに記載されているような方法で、リモートブランチとの差分から対象ファイルを絞り込むこともできます。ただし、eslint
にかかる時間が大幅に短縮されることはなく(せいぜい 1s 程度)、特に絞り込むことは行なっていません。
おわりに
はじめにお伝えしたように、コードチェックはプロジェクトによって適切な方法が異なると考えています。年末の大掃除に合わせて、是非このあたりを見直してみてはいかがでしょうか。
明日は「D&S Div. 紹介記事」を公開予定です。
[1] pre-commit
の実行内容は husky
で設定しています
[2] node_modules
など不要なファイルは除きます
[3] 執筆時点での情報です。頻繁にアップデートされるので、今後変わっていくかもしれません
[4] https://deno.land/ より
[5] 例えば Configuration file の項では
Note that using a configuration file is not required now, and will not be required in the future.
と書かれており、issue でもたびたび言及されています
濱田 翔大
Data-Informed 事業本部 / Technology Div. 所属
運動不足解消のため、VR でのボクササイズにハマっています。フロントエンドのあれこれを発信していきます。