JavaScript
ESLint
VisualStudioCode
Formatter
prettier

2018年のJavaScriptのコードフォーマッター事情

PySpa統合思念体です。

go fmt便利ですよね。設定なしで言語が定めるルールで一発でやってくれるので良いですね。で、JavaScriptでは歴史的経緯もあって、フォーマットの流派はいろいろあります。

  • インデントはスペース2/4、ハードタブ
  • 文字列にはシングルクオート使う派(英語キーボードだとシフトキー押さなくていい)
  • 末尾のセミコロンは必須・省略

そのためカスタマイズ可能なフォーマッターが必要となります。カスタマイズの柔軟性や歴史的経緯や新しい文法への対応などで、いくつかのツールがあります。

フォーマッターの種類

いろいろあります。とりあえず今回の記事で触れるのは以下の4つです。

Visual Studio Codeでお手軽にフォーマットを実行する

Visual Studio Codeにはデフォルトでフォーマッターが内蔵されています。Stack Overflowで見かけた説明によると、js-beatifyベースらしいです。

設定ファイルに次の設定を足せばそれで実行されます。

{
    "editor.formatOnSave": true
}

他にも入力時に自動でフォーマット実行(editor.formatOnType),
タイマーでフォーマットを実行(editor.formatOnSaveTimeout)とか、いろいろあります。フォーマッターの設定は、"javascript.format."以下にいろいろあるので、設定を開いて、設定のフィルタにjavascript.formatと入れると色々出てきます。

Screen Shot 2018-04-29 at 8.41.09 AM.png

なお、プロジェクトフォルダの .vscode/settings.json というファイルに書いておけば、リポジトリを共有すると、Visual Studioさえ使っていれば同じフォーマッターの設定がシェアされます。

Visual Studio Code以外で、最低限、インデントや文字コードを統一

使うエディタがVisual Studioコード以外にもある場合に、基本的な改行コード、エンコーディング、インデント数、インデントで使う文字などを共有する方法としては、editorconfigというものがあります。

Jetbrains製のエディタなどはデフォルトで設定を読んでくれるとのこと。Visual Studio CodeやVimやEmacsなどではプラグインが必要。

ただ、これはフォーマッターとまではいかないですが、チーム内でいろんなエディタを許容するなら最低限やっておきたいですね。なお、Visual Studio Codeだと、.vscode/extensions.jsonに、推奨するプラグインを書いておくと、プロジェクトをオープンした時に自動でインストールするかダイアログで聞いてくれます。

.vscode/extensions.json
{
    "recommendations": [
        "EditorConfig.EditorConfig"
    ]
}

eslintを使う

JavaScriptのコードスタイルチェックで現在一番使われているツールがESLintです。Visual Studio Codeの内蔵機能を使わないで外部ツールを使うのは、CIでテストしたり、他のエディタでも利用したい、というときに必要となります。

ESLintはコードチェッカーですが、一部のインデントなどのコードスタイルの設定に関しては、自動修正ができるため、コードフォーマッターとして利用できます。

$ eslint --fix

なお、さっき紹介したeditorconfigとeslintは連携できません

Visual Studio Codeと一緒に使うには、eslintプラグインを入れます。コードチェックもできるようになりますし、autoFixOnSaveを有効にすると保存時に、eslint --fixしてくれます。ただし、VSCodeデフォルトのフォーマッターと喧嘩するので、editor.formatOnSaveを有効にする場合は内臓機能をオフにします。この機能自体はJS以外でも使われたりするので、JavaScriptの設定だけをオフにすると良いです。

.vscode/extensions.json
{
    "recommendations": [
        "dbaeumer.vscode-eslint"
    ]
}
{
  "javascript.format.enable": false,
  "eslint.autoFixOnSave": true
}

欠点としては、フォーマッターとして利用するには、eslintで細かく設定する必要がありますが、設定ファイルが膨れがちです。いろいろなプラグインの設定が入り混じったりして、eslintの設定ファイルのメンテナンスは大変です。

prettierを使う

フォーマッターに特化したツールとしては、prettierがあります。設定も少なめですぐ実行できます。また、前述のeditorconfigを自動で取り込みます。また、--list-different オプションを付けて実行すると、変更がある場合(スタイルが崩れている場合)にエラーとなるため、CIからも使えるみたいです。

Visual Studio Codeのプラグインもあります。

.vscode/extensions.json
{
    "recommendations": [
        "esbenp.prettier-vscode"
    ]
}

デフォルトのeditor.formatOnSaveをのっとって、js-beautifyの代わりにprettierを実行するみたいです。

現在ベータ版ですが、そのうちpythonとかにも対応するようです。

eslintと比較した場合のマイナス点としては、スタイルチェック以外のコードスタイルチェックのlinting機能が無い点ですね。これについては後述します。また、フォーマット違反のコードを書いても、エディタ内部でエラーとかを表示することはできません。この点はESLintの方が優秀ですよね。CIで漏れが出ないように、といったフォローが必要かと思います。

eslintとprettierの連携

eslintはフォーマット修正にも使えるとはいえ、基本的にはlinterです。ツールを別に使い分ける方法もあります。prettierはeditorconfig以外に、eslintとの連携もできて、設定を一部取り込むことができます。3通りの方法があります。

eslintのプラグインでeslint --fix時にprettierを裏で実行

eslintが主で、prettierが従という方法があります。eslint-prettierプラグイン(VSCプラグインではなくて、eslintのプラグイン)をeslintに設定すると、eslint --fix時にprettierも実行できるようになります。eslint --fix時に自動実行できるので、prettierのVSコードプラグインを入れなくても保存時のコードフォーマットは行なえます。

ただし、prettierに書いたような、エディタ内部でエラーを表示できないという欠点はそのままです。

prettier側で、eslintインテグレーション機能を利用

これとは逆にprettierを主に、eslintを従にもできます。prettier-eslint-cliを使うと、両方の設定ファイルを読み込んで、インデントとかの共通で持っている設定をeslintの方から読み込んでコマンドラインから実行できるようです。prettierプラグインでeslintインテグレーションを有効にすることでも、この機能が使えます(単体のprettier CLIにはこの機能はありません)。

まだ手元で試してはないですが、eslintプラグインはfixOnSaveで保存時にのみ自動実行ができますが、prettierプラグインの場合にデフォルトのフォーマッターを乗っ取るのであれば、タイプ時やペースト時にも実行ができて後者の方が柔軟な気がします。

prettierプラグインを使っていたとしても、eslintのチェックはそれはそれで有用なので、両方を使うというのが良いかと思います。

こちらは、Editorでeslint機能を使う設定にしておくと、フォーマットが期待しないものになっていたら赤線が引かれるようになります。

設定ファイルの連携はせずに、eslintでスタイルに関する設定をすべてはずして、個別のツールで役割を分けて実行する

このようにA→BとB→Aの両方の連携の方法があってどちらにするか迷うのがJavaScriptのよくある課題で、ヤックシェービングが捗るポイントです。いっそのこと、連携しないで独立して使うのも手かと思います。eslint:recommendedの試験項目には、基本的にprettierが行うフォーマットに関する項目は含まれていません(一番左にチェックがついていない)。重複していないので、不要な項目をスキップさせる設定を追加で行う必要もありません。

VSCodeプラグインもそれぞれインストールしてしまえばOKです。eslintのeslint.fixOnSaveはオフにします。エディタの外のCIでは、npm-run-allとかでeslintと、--list-differentつきのprettierを直列実行すればよいでしょう。

ただし、prettierに書いたような、エディタ内部でエラーを表示できないという欠点はそのままです。

まとめ

現時点ではこんな感じかなーと思います。

  • VSCodeで一番カンタンにやるならVSCodeの内蔵フォーマッタ
  • エディタ間で最低限のスタイル(インデントと文字コードと改行コード)ならeditorconfig(他と併用可能)
  • 1つのツールで、CIでも検証しつつ、フォーマットにも利用したいならeslint
  • フォーマットに特化したツールで設定も簡単なのがprettier
  • 複雑になりがちなeslintの設定から、スタイルに関する設定をアウトソースしてシンプルにしておきたいならprettierとeslintの併用もありだが、3つ方法がある
    • eslintのプラグインでeslint --fix時にprettierを裏で実行(prettierプラグインインストール不要)
    • prettier側で、eslintインテグレーション機能を利用
    • 設定ファイルの連携はせずに、eslintでスタイルに関する設定をすべてはずして、個別のツールで役割を分けて実行する

まとめるとこんな感じかと。

手法 pros cons
VSCode標準 とにかく簡単 CIや他のエディタから利用ができない
EditorConfig いろんなエディタ/IDE環境に対応 設定できる項目が少ない
ESLint linting/format両対応でformat違いもエディタで表示が出る 設定が複雑になりがち
Prettier 設定が簡単 Linterがない&format違いをエディタに表示できない
ESLint&Prettier 設定が比較的簡単でlinting/format両対応 設定方法が複数ある。eslintプラグイン以外の方式だと、format違いをエディタに表示できない

個人的にはESLint&Prettierで、疎結合で別々に利用するという方向で試してみようと思っています。