⚒️

【Flutter】自動フォーマットのLine lengthをプロジェクトで統一する

2024/05/08に公開

はじめに

Android Studio, IntelliJ IDEAやVSCodeの自動フォーマット機能を使ってDartコードをフォーマットする場合、エディタのプラグイン設定であるLine lengthの値によってフォーマットが行われます。


Android Studio(Settings->Editor->Code Style->Dart)

VSCode(Settings->Extensions->Dart->Editor)

そのため、チームメンバーが設定しているLine lengthによってはフォーマットの結果が異なることとなり、差分が発生します。
全員がデフォルトを使用していればよいのですが、デフォルトのLine lengthである80は現代の環境だと余白を持て余してしまうことが多いため、80以上を設定している開発者も少なくなさそうです。

デフォルトの80を使う場合はLinterルール「lines_longer_than_80_chars」を設定できたり、また、dart format --line-length=80 .コマンドを使えばLine lengthを指定したフォーマットを行うこともできます。
しかし、自動フォーマットのLine lengthがエディタのプラグイン設定に依存している限り、開発中に自動フォーマットを行うたびに無用な差分が発生してしまいます。
「Format code on save」をオンにしている開発者も多いと思います(VSCodeはデフォルトでオン)。
そして、これを解決する、プロジェクト毎にyamlファイル等でLine lengthを指定するような方法は今のところありません。

本記事は、プロジェクト毎に統一の自動フォーマットを適用するためのプラクティスを紹介します。

エディタの設定ファイルを定義してgit管理する

Android Studio, IntelliJ IDEAとVSCodeには、それぞれ、プロジェクト毎に定義した設定ファイルの設定項目を、デフォルトの設定に優先させたりオーバーライドする機能があります。

これらの設定ファイルにプラグインのLine lengthの設定を定義することができ、さらにこの設定ファイルをgit管理することで、Line lengthのプラグイン設定を共有することができます。

Android Studio, IntelliJ IDEA

https://github.com/Dart-Code/Dart-Code/issues/1715#issuecomment-740483365

Android Studio, IntelliJ IDEA向けには、.idea/codeStyles/のパスにcodeStyleConfig.xmlProject.xmlを追加し、それぞれ以下を記述します。

.idea/codeStyles/codeStyleConfig.xml
<component name="ProjectCodeStyleConfiguration">
  <state>
    <option name="USE_PER_PROJECT_SETTINGS" value="true" />
  </state>
</component>
.idea/codeStyles/Project.xml
<component name="ProjectCodeStyleConfiguration">
  <code_scheme name="Project" version="173">
    <codeStyleSettings language="Dart">
      <option name="RIGHT_MARGIN" value="80" />
    </codeStyleSettings>
  </code_scheme>
</component> 

VSCode

https://stackoverflow.com/questions/59456452/how-to-change-dart-line-length-in-vscode-when-formatting-dart-files

VSCode向けには、.vscode/のパスにsettings.jsonを追加し、以下を記述します。

.vscode/settings.json
{
    "dart.lineLength": 80, // 自動フォーマットのLine length
    "[dart]": {
        "editor.rulers": [80], // ルーラーのLine length
    }
}

設定ファイルを追加してプロジェクトを開くと、以下のように設定ファイルの追加が反映されていることがわかります。

Android Studio(Settings->Editor->Code Style->Dart)

VSCode(Settings->Extensions->Dart->Editor)

そして、この.idea/codeStyles/.vscode/settings.jsonをgit管理します。
Flutterプロジェクトデフォルトの.gitignoreでは.idea/が除外されているので、.idea/*に変更して!.idea/codeStyles/を追加するとよいです。

これで、プロジェクトをクローンしていずれかのエディタで開けば、設定ファイルで指定したLine lengthで自動フォーマットができる環境ができました。

(+α)フォーマットのバリデーション

さらに、マージされるコードが正しくフォーマットされているか確認するには、以下の方法があります。
冒頭の通り、dart format --line-length=80 .コマンドでLine lengthを指定したフォーマットを行うことができました。
そして、以下のパラメータを追加することで、フォーマットが正しくない場合はフォーマットを行わずexit 1を返却します。

dart format --line-length=80 --output=none --set-exit-if-changed .

これをgitのpre-pushフックやCIのワークフローなどに組み込むことで、指定したLine lengthでコードがフォーマットされていることを保証できます。

https://github.com/dart-lang/dart_style?tab=readme-ov-file#validating-files

Validating files

If you want to use the formatter in something like a presubmit script or
commit hook, you can pass flags to omit writing formatting changes to disk
and to update the exit code to indicate success/failure:

$ dart format --output=none --set-exit-if-changed .

おまけ

dart-lang/dart_styleには、Line lengthをエディタのプラグイン設定としてではなくプロジェクトの設定として追加しようというIssueが立っていて、 設定を追加することに消極的なメインコミッターBob氏(@munificent)と開発者との間で4年も前から議論がされています。
Line lengthをプロジェクトの設定として追加するべきかという論点と、デフォルトの80は短すぎるだろいつの時代だよという論点が混じっていてカオスな感じですが、面白いので読んでみてください。
https://github.com/dart-lang/dart_style/issues/918

最後に、Bob氏が設定を追加すること(Line lengthに関わらず)に消極的な背景として、自身が編集しているWikiのFAQを引用していたので、紹介します。

Dartフォーマッターには、いくつかの目標があります。優先順位の高い順に、

  1. 一貫した形式のコードを生成する。 (略)
  2. コードレビューにおけるスタイルの問題に関する議論を終わらせる。 (略)
  3. フォーマットについて考え、適用する必要をなくす。 (略)
  4. コードを理解するのに役立つ、美しくリーダブルな出力を生成する。 (略)

(略)

なぜ設定できない?

Dartフォーマッターは設計上、設定の調整をほとんどサポートしていません。上の優先順位のリストを見ると、設定可能にすれば最初の2つの優先順位に直接反し、3番目の優先順位には半分反する(考える必要はあるが、適用する必要はない)ことがわかるでしょう。

驚くかもしれませんが、Dartフォーマッターのゴールは、あなたのコードを自動的にあなた好みのものにすることではありません。全員のDartコードが同じように見えるようにすることです。Dartフォーマッターの主な目的は、Dartのエコシステムの品質を向上させることです。再利用できるコードが増え、より一貫性のあるコードになり、お互いのコードが読みやすく、またコントリビュートしやすくなります。しかし、それは個人の好みを犠牲にすることになります。

一貫性のあるエコシステムは、個人のフォーマットの好みよりも価値があるという考えを受け入れる必要があります。別の言い方をすれば、一貫性のなさや、自分のチームの独自スタイルがどうあるべきかを議論しなければならないコストを補ってもなお、独自フォーマットスタイルがDartフォーマッターが生み出すものよりもよほど優れているというようなことはないということです。

これを受け入れないとしても、それはOKです。おそらくあなたにとってDartフォーマッターは適切なツールではないということでしょう。

(筆者訳)
https://github.com/dart-lang/dart_style/wiki/FAQ#why-cant-i-configure-it

参考

https://github.com/dart-lang/dart_style
https://docs.flutter.dev/tools/formatting
https://dart.dev/tools/dart-format
https://github.com/Dart-Code/Dart-Code/issues/1715#issuecomment-740483365
https://www.jetbrains.com/help/idea/configuring-code-style.html
https://stackoverflow.com/questions/59456452/how-to-change-dart-line-length-in-vscode-when-formatting-dart-files
https://code.visualstudio.com/docs/getstarted/settings#_workspace-settings
https://github.com/dart-lang/dart_style/issues/918
https://github.com/dart-lang/dart_style/wiki/FAQ

株式会社Never

Discussion