Prettierを使わない理由
はじめに
Prettierはコードフォーマッターとして広く使われているツールです。
コードスタイルに関する議論をなくすこと
を目的としており、ESLintとは異なりデフォルト設定のままですぐに使えるのが特徴です。
さらに、PrettierはJS以外にもHTMLやCSS、Markdownなどのフォーマットにも対応しています。
そして、ESLintでは自動修正が難しい部分(max-len等)もPrettierを使えば自動で修正できるため、ESLintよりも優れた点が多くあります。
そんなPrettierの利点を紹介しましたが、正直なところ私はPrettierをあまり好きではありません。
この記事では、私がPrettierを使わない理由を説明したいと思います。
printWidthが強すぎる
Prettierはデフォルトで80文字で折り返しを行います。
これはコードを読みやすくするための設定ですが、読みやすさのためにあえて改行していない所も強制的に改行されます。(逆も然り)
// prettier-ignore
とコメントする事で、Prettierのフォーマットを無効に出来ますが、ignore
するかどうかは実装者次第です。
実装者によってはignore
して読みやすく書く人もいれば、ignore
しないでPrettierに任せてしまう人もいるかもしれません。
これでは、Prettierの利点であるコードスタイルの一貫性が失われてしまいます。
配列定義
将来的に要素が増える可能性がある配列を定義する場合、下記のようにPRのDiffが見やすくなるように改行しておくことがあります。
const arr = [
elment1,
elelment2,
elment3,
+ element4,
];
しかし、Prettierを通すと下記のように置き換えられてしまいます。
const arr = [elment1, elelment2, elment3];
関数呼び出し
関数呼び出しの引数が多い場合、可読性の為に下記のように改行しておくことがあります。
func(
arg1,
arg2,
arg3,
);
しかし、こちらも関数定義と同様にPrettierを通すと下記のように置き換えられてしまいます。
func(arg1, arg2, arg3);
メソッドチェーン
メソッドチェーンを行う場合、下記のように改行しておくことがあります。
const test1 = func()
.chainMethod()
.chainMethod()
.chainMethod()
.chainMethod();
const test2 = func()
.chainMethod()
.chainMethod()
.chainMethod()
.chainMethod()
.chainMethod();
const test3 = func()
.chainMethod()
.chainMethod()
.chainMethod();
しかし、Prettierを通すと下記のように置き換えられてしまいます。
const test1 = func().chainMethod().chainMethod().chainMethod().chainMethod();
const test2 = func()
.chainMethod()
.chainMethod()
.chainMethod()
.chainMethod()
.chainMethod();
const test3 = func().chainMethod().chainMethod().chainMethod();
改行されるかどうかは、PrettierのprintWidth
に依存し、読みやすさの為の改行は全て無視されます。
読みやすさを優先したいのであれば、下記のように// prettier-ignore
を付けるしかありません。
// prettier-ignore
const test1 = func()
.chainMethod()
.chainMethod()
.chainMethod()
.chainMethod();
// prettier-ignore
const test2 = func()
.chainMethod()
.chainMethod()
.chainMethod()
.chainMethod()
.chainMethod();
// prettier-ignore
const test3 = func()
.chainMethod()
.chainMethod()
.chainMethod();
ESLintと被る部分が多い
Prettierを使う場合、ESLintと併用して使う方は多いと思います。
ESLintはLinterとFormatterの両方の機能を備えている為、Prettierと併用する場合には幾つかのルールが重複してしまいます。
そのため、eslint-config-prettierを使ってESLintのフォーマット関連のルールを無効にすることが推奨されています。
以下は、eslint-config-prettier
が実際に無効にするルールの一覧です。
これだけ多くのルールを無効にするのであれば、ESLintのみを使用してコードフォーマットを行う方がよりシンプルではないでしょうか。
また、ESLintにはデフォルトの設定はありませんが、recommendedという推奨されるルールのプリセットが用意されています。
コードスタイルに関する議論をなくすこと
を目的とするならば、ESLintのrecommendedを使用するだけで十分ではないでしょうか。
ESLintのPluginの選定ですら面倒なのであれば、eslint-config-airbnbや@antfu/eslint-configのようなプリセットを使うこともできます。
実際に、私が所属するチームではESLintのみを使用していますが、コードスタイルに関する議論はほとんど発生していません。
ESLintと競合するルールを無効化する必要があるという複雑さが増えることが、私がPrettierを使用しない理由の一つです。
まとめ
Prettierには、全員に同じコードスタイルを強制できるという利点がありますが、場合によっては好ましくないスタイルも強制されることがあります。
ESLintだけでもコードのフォーマットは十分可能ですし、今のところPrettierを使用していれば良かった等と困ったこともありません。
Prettierに限らず、ツールを導入する際はメリットとデメリットをしっかり理解し、自分たちのチームに最適なツールを選択することが重要だと思います。
Discussion
失礼します。ご存知だったら恐縮ですが、
僕は、prettier (および biome) に潰されてほしくない改行は、
//
コメントを使って固定しています。これなら、改行以外のルールを無効にせず改行の位置のみをコントロールできます。三項演算子以外は、これで何とかなっています。
その手段も知っていますが、
// prettier-ignore
と同様に//
を使用するかどうかは実装者次第だと思います。この方法ではPrettierの利点である
コードスタイルの一貫性
が失われてしまうため、それであればESLintのみで運用する方が良いのではないかというのが私の考えです。(そもそも
//
ってhackyな感じがするけどPrettierが公式にサポートしている機能なのかな・・・)ご存知だったんですね💦 失礼しました
あと、僕は prettier にまかせて、eslint にフォーマットをさせないのが当たり前でやってきたので、eslint に寄せるとどうなるのかよく考えてなかったです
ESLintのフォーマットが過小評価されていると感じたのがこの記事を書き始めたキッカケでした。
なので、この記事を通して「ESLintでもフォーマット出来るんだ」と考え直す機会になる事ができて嬉しく思います。
eslintのフォーマッターは最新のバージョンでdeprecatedされてます。
個人的にはdprintが好きです。
そちらの記事でも言及されていますが、フォーマット関連のルールはESLint Stylisticという形でPluginとして切り出され、Anthony Fu氏がメンテナンスを行っています。
Anthony Fu氏はVitestやSlidev等の有名なOSSの作成者であり、今後も継続的なメンテナンスが期待できるでしょう。
karibashさんのこの記事を見たときに真っ先に思い浮かんだのはAnthony Fuさんの「Why I don't use Prettier」という記事でした。
Karibashさんはご存じのことかと思いますが、この記事を見た方向けに紹介させていただきます。
いつ別の人に引き継ぐかもしれない企業コードでオリジナリティだす勇気。
こういう人がやめてった後のコードは大変じゃないです?
そう思うとprettierは確かにアレな部分もあるけど一般化してしまった以上、
他の人の気持ちを考えれば別の手段は取れない…
何をもって
ESLint + Prettier
の組み合わせが一般化していると定義するのかが難しい所ですね。正確な値は導き出せないかもしれませんが、npmの週間ダウンロード数から推測してみましょう。
ESLint
及び、ESLint
とPrettier
を組み合わせる場合に使用する事が多いeslint-config-prettier
の週間ダウンロード数を調べてみたところ下記の通りでした。この事から、ESLintを利用している方の約53%がPrettierと組み合わせている可能性があるという事が推測できます。
ESLintのみを使用している方は約47%存在するという点から、Prettierを使わないという選択肢は必ずしも異端という訳では無さそうに思えます。
前述の事から、ESLintのみを使用しているユーザーは約47%という事が分かるので、これをオリジナリティと表現するのもあまり適切では無いかなと思います。
コード実装者がフォーマットについて思考する必要がないということと
コード実装者が実装意図をフォーマットとして表現する機会を喪失することを天秤に掛ければいいのかなと思いました。
個人的にはコードレビューの観点も含めるといい意思決定ができるのかなと思います。
実装意図がかき消されたコードレビューはかなりきついと思っています。
これわかります。
機械的に長さを制限するメリットが
読みやすさを破壊するデメリットを下回る事が多々あって、それを毎回ignoreするのも違うなぁと。
ESLintも試してみて、今後どうするかまた判断しようと思います!
ありがとうございました。
それを言ってしまうと読みやすさのためにあえて改行を入れるかどうかも実装者次第では...
あえて改行を入れたり入れなかったりしているとき、Prettierを導入していないときは修正し忘れなのか意図的なのかわかりませんが、導入していると
// prettier-ignore
があるので意図的であることがわかるというメリットもある気がします。おっしゃる通り、それも実装者次第だと思います。
ですが、ESLintの場合はわざわざ
// prettier-ignore
や//
を入れなくて良いメリットがあります。まとめの項にも記載していますが、Prettierを使用すると全員のコードスタイルを強制できますが、場合によっては好ましくないスタイルも強制されてしまい、それを無視するためには
ignore
しないといけないのがPrettierを使わない理由です。ESLintだけでも十分にフォーマット可能ですし、フォーマットに従いつつ必要があればより良い書き方をすることもできます。
気持ち的にフォーマッターは可能な限り
ignore
したくないという所があったので、その観点は私も抜けていました。貴重な意見を頂きありがとうございます!
複数の似たようなコードを書いているのに、改行有無で似たように見えなくなってしまうのはかなりストレスを感じます。
慣れというのはいろいろなことを見えなくしてしまうもので、ストレスを感じるたびに
//
を使うプラクティスで直すところまでが当たり前になっていました。だけど「なんかきれいじゃない」という感覚はありました。Prettier を使わない設定、試してみます!
みんなでBiomeに行こうぜ
各所に読みやすさの為というワードが出てくるけど、冒頭にもある通りコードスタイルに関する議論(誰かの主観である読みやすさについての議論)をなくすことを目的に入れているので、使わない理由としては正しいと思う。
ただ、最後の最後で「Prettierを使う人は周囲のエンジニアが使っているからという理由だけで導入している」というディスともとれるようなことを書かれると反論したくなる。
その「誰かの読みやすさ」とかいうこだわりに付き合いたくないから入れてます。
改めて見返してみると、確かにディスと受け取ってしまいかねない表現だなと思いました。
文言修正しておきます。貴重な意見を頂きありがとうございます!
こういう部分もあるよっていうの共有してくれたのありがたいです。
たしかに必要になったらprettier導入とかでもいいのかも、
アルファベット順にimport並び替える設定と
typeの前にこれをimportしなきゃダメだよってルールが競合してコンパイルできなくなったことあるから、
そしてprettierとeslintどっちがどのルールを適用してるとかもちゃんと把握してなかったから問題の修正が大変だった記憶がある、、
しかもvscodeのformat on saveでimportの順序が最終的には入れ替わってないのに一瞬ちらっと入れ替わってるような動作してたし、
まずeslintとか使って、こういう風にしたいけどeslintじゃできないっていうのが出てきたら導入してみたいと思います!