フロントエンドの基盤開発をしている、みゅーとんです。
弊社のプロジェクトでは、実装開始初期から、コードフォーマットするルールがありませんでした。
コードフォーマットを全体に強制させる方法として、最も手間最小で時間がかからない方法を模索し、
これでストレスなく自動フォーマット (eslint, prettier) を回せるようになったので、
試行錯誤していた頃の方法も含めて紹介します。
前提
前提として、eslint, prettier がインストールされていて、設定値の整備が完了しているものとします。 設定値については今回は取り上げません。
具体的には、以下のコマンドでインストールがされていて
yarn install -D eslint prettier eslint-config-prettier
package.json の devDependencies に eslint
prettier
があり、 npm script から実行できる状態になっているとします
package.json
{ // ... "scripts": { "format": "eslint . --fix --cache --ext .js,.ts,.vue --ignore-path .eslintignore && prettier . --write --ignore-path .prettierignore", }, // ... "devDependencies": { "eslint": "8.24.0", "eslint-config-prettier": "8.5.0", "prettier": "2.7.1" }, // ... }
試行錯誤1 .. vscode 共通設定
vscode で共通の拡張機能設定を使うなどの理由で、 ./.vscode/
配下に vscode 用のワークスペースファイル ( project.code-workspace
) を配置し、git で管理していました。
.vscode/project.code-workspace
{ // 中略 "settings": { "editor.codeActionsOnSave": { "source.fixAll.eslint": true, "source.fixAll": true }, "editor.formatOnSave": true, "editor.format.enable": true, "editor.defaultFormatter": "esbenp.prettier-vscode", "eslint.packageManager": "yarn", "npm.packageManager": "yarn" }, "extensions": { "recommendations": [ "dbaeumer.vscode-eslint", "esbenp.prettier-vscode" ], } }
良かった点
保存直前にフォーマットされるのは一番手間がかからず良かったです。 フォーマット漏れを確実に防げる方法でもありました。
問題点
この方法では、 vscode 以外での開発に差し支えが出てくることが想定されるとおもいました。
また、エディタ含む各自の開発環境ごとに挙動が異なることも判明しました。
vscode の設定では、 “推奨される拡張機能” を設定できますが、拡張機能のインストールを強制することができず、環境によって拡張機能の有無に差が生まれました。
開発環境依存となる要素は極力避けるべきと判断し、この方法はボツとしました。
試行錯誤2: husky
huskyは npm パッケージの1つで、 コミット, プッシュ時などの任意のタイミングでコマンドを自動実行してくれます。
これを使って、コミット直前に prettier を実行する方法を考えてみました。
インストール方法
- 以下を実行
npm install -D husky # 以下は各環境ごとに実行 npx husky install
- 設定ファイルを用意
以下を実行し、.husky/pre-commit
を作成
npx husky add .husky/pre-commit "yarn format"
良かった点
開発環境自体に影響がなく、快適でした。
また、コミット直前に format を実行してくれるので、漏れにくいのも良かったです。
node_modules 配下で管理することにはなりますが、 husky 自体が他のモジュールへの依存をもたないため、管理自体は用意でした。
問題点
フォーマット結果に差分が発生した際でも、コミットがそのまま実行されてしまうので、
フォーマットをコミットに含めるためにわざわざ git commit --amend
をせざるを得ませんでした。
(lint-staged と組み合わせることで回避できるようですが、今回はそこまで検証しませんでした。)
また、同じリポジトリに JS 以外のコード (本件では terraform) を追加する必要がでてきてしまい、 JS 向けのフォーマットか、 terraform 向けのフォーマットかを shell 内に if 文で分岐するような実装が求められるようになりました。
husky 側で、どのファイルが変更されたかで分岐は可能ですが、将来性を考えるとメンテが大変そうで、導入を断念しました。
試行錯誤3: pre-commit
機能は husky に似ていますが、npm ではなく brew でインストールできます。
インストール方法
- インストール
brew install pre-commit
- 設定ファイルを用意
.pre-commit-config.yaml
を以下の通りに作成
repos: - repo: https://github.com/pre-commit/mirrors-eslint rev: v8.24.0 # ← package.json に記載のバージョンに合わせる hooks: - id: eslint - repo: https://github.com/pre-commit/mirrors-prettier rev: v2.7.1 # ← 同上 hooks: - id: prettier
良かった点
コミット直前に実行され、 ステージングされているファイルのみに対してフォーマットが実行されました。
差分が発生した場合はコミットが実行されないため、フォーマット分がコミットから漏れる心配もなくなりました。
また、前述する terraform 向けのフォーマットとの共存も簡単に実装できました。
問題点
弊社では開発メンバーは全員macであるため、インストール方法も統一されていますが、
そうではないケースでは少し環境差異がありそうに感じました。
まとめ
メンテしやすく、確実にコミットにフォーマットを含めるには pre-commit が一番良さそう、という結論に至りました。