🐈

2023 年の Prettier 振り返り

2023/12/27に公開

2023 年の Prettier の活動を振り返ります。

Prettier とは

Prettier は JavaScript で書かれたコードフォーマッタです。設定可能な項目が少ないいわゆる opinionated なコードフォーマッタです。JavaScript や TypeScript だけではなく、HTML や CSS、GraphQL などもサポートしています。

リリース

2023 年は、メジャーバージョンのリリースが 1 回、マイナーバージョンのリリースが 1 回でした。これまでは 3 ヶ月に 1 回程度マイナーバージョンをリリースしていたので、頻度は少し下がっています。

ですが、メジャーバージョンである 3.0 をリリースできたことと、これまでよりもカジュアルにパッチバージョンをリリースするようになったことを考えると、開発自体が停滞しているわけではないと思っています。

「カジュアルにパッチバージョンをリリースするようになったこと」について例をあげます。TypeScript 5.2 から Explicit Resource Management という機能が実装され、それにともなって using / await using という新しい構文が追加されました。Prettier はこの機能をサポートする必要があります。これまでは、Prettier にとってこれは semantic versioning における functionality とみなして、マイナーバージョンとしてリリースしていました。しかし、最近では「TypeScript の新機能に追従できていない状態から修正する」という bug fixes とみなして、パッチバージョンとしてリリースしています。実際 using / await using のサポートは Prettier 3.0.3 としてリリースされました。

これについては賛否両論あるかもしれませんが、個人的にはパッチバージョンとしてリリースできる方が楽なので助かっています。

Prettier 3.0

Prettier 3.0 は2023年7月5日にリリースされました。実に、約3年ぶりとなるメジャーリリースです。主な変更は以下です:

  • Markdownのフォーマットで、日本語とラテン文字の間にスペースが挿入されなくなった
  • 非同期のパーサーを書けるようになった
  • 設定ファイルをECMAScript Modulesで書けるようになった
  • trailingComma オプションのデフォルト値がes5からallになった
  • プラグインをECMAScript Modulesで書けるようになった
  • ソースコードがすべてECMAScript Modulesで書かれるようになった

ユーザー影響のある機能はそこまで多くありませんでした。日本語を使う人にとってはMarkdownのフォーマッタの変更の影響は大きかったかもしれませんが、そうでない人は特に影響を感じなかったかもしれません。

Prettier 開発チームにとっては、ソースコードがすべてECMAScript Modulesで書かれるようになったのは大きな変更でした。これにはいくつかのメリットがありました。

まずは、バンドルサイズを小さくするための技術を適用しやすくなったことです。バンドラによる Tree Shaking などの静的解析の技術は基本的には CommonJS Modules よりも ECMAScript Modules の方が効きが良いことが多いです。また、Sindre Sorhus氏 や @wooorm氏などが開発する Pure ESM Package を使うための嫌なハックを取り除くことができました。

これは私の主観ですが、CommonJS より ECMAScript Modules の方が(普段仕事でも書いているから)書きやすいので、その点でもありがたい変更でした。一方で、prettier-vscode が動かなくなり、ものすごく苦労したというデメリットもありました。

主な機能は @fisker が実装してくれました。私はいくつかの機能とバグ修正、そしてこのリリースに何を入れて何を入れるべきでないかを考えたり、リリースブログを書いたり、リリースをしたりといった細かい(が大量の)作業をしました。

Prettier 3.0 の詳細については 公式のリリースノート を参照してください。

Prettier 3.1

Prettier 3.1 は2023年11月13日にリリースされました。

このバージョンでは三項演算子のフォーマットに大きな変更がありました。もともと Prettier は、三項演算子がネストするたびにインデントを追加するようにフォーマットをしていました:

const message =
  i % 3 === 0 && i % 5 === 0
    ? "fizzbuzz"
  : i % 3 === 0
    ? "fizz"
  : i % 5 === 0
    ? "buzz"
    : String(i);

この振る舞いは 2018 年にインデントをしないように変更されました。しかし、この変更は多くのユーザーにとっては受け入れがたいものだったようです。この変更を受け入れられなかったユーザーからの issue が起票されてから 5 年ほど経ってしまいましたが、Prettier 3.1 ではインデントを追加する挙動に戻しました。

ですが、Prettier チームはこのインデントありの三項演算子のフォーマットも決して理想的なものではないと考えています。普通に読みにくいですよね。そこで、この問題に対して大きな関心を持っていた Alex Rattray 氏を中心として理想の三項演算子について探求しました。そして、Prettier 3.1 ではそのフォーマットを試験的にリリースしました。--experimental-ternaries というオプションを付けて実行することで、三項演算子の試験的なフォーマットを試すことができます。

新しい三項演算子の試験的なフォーマットの具体的な挙動については、公式ブログもしくはその日本語訳を参照してください。フィードバックを募集しているので、ブログに貼ってある Google Forms のリンクからアンケートに答えてくれると嬉しいです。

もともと、この試験的な三項演算子のフォーマットは3.0でデフォルトで有効にしてリリースしたいという話になっていました。個人的にはこのフォーマットは気に入っていますが、ユーザーとのハレーションを考えると、いきなりデフォルトで有効にするのはやりすぎだと思いました。なので、試験的フラグと廃止フラグという概念を導入して、ユーザーからのフィードバックを得ながら徐々に導入していくことにしました。

三項演算子の他には、Angular v17 で Developer Preview となった built-in control-flow と defferable views という機能のための構文のサポートが実装されました。この機能については別途ブログを書いたので、気になる人は Prettier の Angular サポートの仕組みと built-in control flow 対応 を参照してください。

自分の 3.1 の主な仕事はこのあたりの調整でした。

Prettier 3.1 の詳細については 公式のリリースノート を参照してください。

Biome と Prettier

知っている人も多いかもしれませんが、3.1 をリリースした直後には「PrettierをRustで書き直したやつに$20kあげちゃうキャンペーン」が開催されました。これは Prettier の co-creator である @Vjeux 氏によって企画されたものです(氏は React Native の co-creator としても知られている Meta のソフトウェアエンジニアです)。

結果的にこの報奨金プログラムは Biome のフォーマッタが勝利しました。詳細については公式ブログもしくはその日本語訳を参照してください。

せっかくなので、このプログラムに対する個人的な気持ちを書きます。

プログラム自体について私はポジティブな立場です。Prettier が誕生してから 6 年程度が経とうとしていますが、これまで競合となるソフトウェアが存在しなかったため、パフォーマンスなどの非機能要件の改善がおろそかになっていました。これは業界全体にとっては良いことではありません。今回 Biome が Prettier との互換性と資金とコントリビュータを手に入れたことで、Prettier にとっては驚異的な競合になりました。これは良いことです。

しかし技術的には、Rust で書き直すことが良い結果になるということに私は確信を持てていません。これにはいくつかの観点があります。

あらかじめ明言しておきたいのですが、Biome や Rust のことが嫌いとかそういうことではなくて、人々に求められるパフォーマンス要件を満たすコードフォーマッタを開発する言語として、Rust が適切なのかと言われるとそうではない可能性もあるよね?というくらいの話です。

コードフォーマッタに求められるパフォーマンス要件

まず、コードフォーマッタに求められるパフォーマンス要件は、トランスパイラやバンドラに比べるとそこまで高くないだろうという前提があります。ローカルでの開発ではテキストエディタの拡張を使って format on save で実行することが多いでしょうし、CI の実行時間についても支配的になるのはビルドであることが多い気がします(どうですかね)。

速く書こうとした JavaScript は十分速いのではないか

次に、そのパフォーマンス要件は JavaScript のままでも十分に達成できるのではないかということです。

Prettier もそうですが、webpack や Babel などの JavaScript で記述された JavaScript のためのツールの多くは、当時はそこに存在するかどうかもわからなかったニーズを顕在化させた立場であることが多いです。たとえば、JavaScript の業界に opinionated なコードフォーマッタが必要とされていたということは、Prettier の流行をもって示されたといえるでしょう。これらのツールはそもそも速くしようと思って作られていなかった可能性が高いのです。少なくとも Prettier は速くしようと思って作られてはいませんでした。

なので、現時点では遅くて当然なのです(もちろん、それが良いということではないです)。速くしようと思って作られていないソフトウェアが遅いのは言語に関係なく当然です。C言語で書いてもRustで書いても遅いプログラムは遅いし、逆に JavaScript が書かれたプログラムのパフォーマンスのボトルネックが JavaScript であることはそんなにないのではないでしょうか。

実際、Prettier の CLI を TypeScript で 1 から書き直したところ 5 倍くらい速くなったという結果が出ています。これは主に glob パターンの解析、設定ファイルの解決などの改善によるものです。

また、Prettier で TypeScript をフォーマットするときの一番のボトルネックはパーサーなのですが、今 Prettier が使っている TypeScript のパーサーはアーキテクチャ的にどうやっても遅いので、これをもっと高速なもので置き換えると結構速くできるんじゃないかなーと思っています。

おわりに

2023 年は新しいメジャーバージョンのリリースと強力な競合の登場などがあり、Prettier にとっては大きな一年でした。

来年は、よりパフォーマンスを意識した一年になるでしょう。Prettier がよりよいソフトウェアになることに興味がある人は https://opencollective.com/prettier から支援をお願いします。今度、Prettier の資金に関するブログも書こうと思います。

Discussion