FORCIA CUBEフォルシアの情報を多面的に発信するブログ

マッチョすぎるフォーマッターPrettierをESLintに統合してみた

2018.12.08

アドベントカレンダー2018 テクノロジー

FORCIAアドベントカレンダー2018の8日目の記事です。

 技術本部の乙村です。最近、Prettier というフォーマッターがきてると聞いたので、触ってみました。「いま ESLint の設定に沿ってフォーマットをしているけど、Prettier 導入したらどうなるか試してみたい」と興味を持たれている方向けに、その特徴と導入の仕方を紹介します。

Prettier とは

 Prettier は以下の特徴を持つフォーマッターです。(https://prettier.io/ #What is Prettier? より抜粋)

  • An opinionated code formatter ("opinionated" である)
  • Supports many languages (多言語サポート)
  • Integrates with most editors (多くのエディターとの統合が可能)
  • Has few options (限られたオプション)

 公式サイトにある説明のとおり、Prettier は JavaScript 専用のフォーマッターではなく、HTML、CSS 、Markdown など広いファイル種類をサポートする汎用のフォーマッターです。また、Visual Studio Code や Vim などのエディターと統合し、ファイル保存時に自動でフォーマットさせることも簡単にできます。

 ただやはり最大の特徴は "opinionated" であることだと個人的には思っています。直訳では「独断的な」とか「自説を曲げない」という意味ですが、意訳すると「みんなフォーマット方針ってどういうものがいいと思う?自分はこれがいいと思う!だから従ってね」ってことです。もっと具体的にいうと「インデント?空白2つに決まってるだろ!タブとかないわー」ってことです。マッチョですね。

 方針があらかじめ決まっているので、フォーマットスタイルを変更できる余地もあまりなく、これが「限られたオプション」の特徴に繋がります。例えば、ESLint はスタイルに関するオプション(Rules - Stylistic Issues) だけで180 近くあるのに対して、Prettier のオプション (Options · Prettier)は 18しかありません。

 公式サイトの Why Prettier? には以下のように書かれています。

By far the biggest reason for adopting Prettier is to stop all the on-going debates over styles.
(Prettier を採用する最大の理由は、スタイルに関する全ての議論を止めるためです)

 Prettier はフォーマットツールでありながら、「これでいいんじゃない」というフォーマット方針も与えてくれるところにその独自性があります。不自由なようにも見えますが、逆に言えば「こちらで細かく決めなくてもいい感じにフォーマットしてくれる」という魅力があります。

Prettier の導入

 JavaScript のフォーマットを目的とした Prettier の導入方法について説明します。

 Prettier はあくまでフォーマッターなので、ESLint でいう no-unused-vars (未使用の変数を許可しない)などのコード品質にかかわる指摘と修正はできません(参考:Prettier vs. Linters)。ですので、現実的にはリンターと併用するケースが多いはずです。ここでは、ESLint が既に導入されているという前提で、ESLint に Prettier によるフォーマットを統合する方法を紹介します。

Prettier のインストール

1. npm または yarn で、必要なパッケージ (prettier, eslint-config-prettier, eslint-plugin-prettier )を インストールする

npm i -D prettier eslint-config-prettier eslint-plugin-prettier

2. eintrc の extends の最後に Prettier 用の設定 plugin:prettier/recommendedを追加する

module.exports = {
    "extends": [
       "standard", // https://github.com/standard/eslint-config-standard
       "my-awesome-format-rule", // ぼくが考えた最強のフォーマットルール
       "plugin:prettier/recommended" //  Prettier の設定(★これが大事)
    ],
}

これで Prettier のデフォルト設定でフォーマットする準備ができました。

"plugin:prettier/recommended" の設定は Prettier のフォーマットルールを適用するだけでなく、既にあるフォーマットルール(この例だと "standard""my-awesome-format-rule" 内のフォーマットルール)を「無効にする」働きもしているため、extends の最後に書く必要があります。

動作確認

 コマンドラインで eslint を実行してみて prettier/prettier という種類のエラーが出ていれば、それが Prettier によるフォーマット違反の指摘です。

$ npx eslint target.js
  125:1   error  Replace `↹↹↹↹↹↹[colName]·` with `··········[colName]` prettier/prettier

 これは「タブがフォーマットルールに違反しているので、空白に変換してください」というエラーですね。eslint --fix で自動的に修正(フォーマット)が可能です。修正前後でどう変わるか確認してみてください。

自動フォーマットの設定

 勝手にフォーマットしてくれないと全然嬉しくないので、eslint --fix をセーブ時に自動的に行うようにします。設定はエディタごとに異なるので、お使いのエディタの設定方法を確認してください。Integrations - ESLint - Pluggable JavaScript linter

私は Visual Studio Code を使っているので、

を行いました。

フォーマットルールの調整

 前述のとおり、Prettier は基本的なフォーマット方針を決められているところがウリですが、とはいえ今までインデントにタブを使っていたのが空白になるなど、「これまで使ってたフォーマット方針とあまりにギャップがありすぎる......」という感想を持つ方もいるかもしれません。この場合はrules に Prettier の設定を追加することで、ある程度調整が可能です。

<参考>Options · Prettier
https://prettier.io/docs/en/options.html

設定例
module.exports = {
  extends: ["airbnb-base", "plugin:prettier/recommended"],
  rules: {
  "prettier/prettier" : [
    "error",
    {
     // 設定可能なオプションの一部. () はデフォルト値. 
      printWidth: 100,   // 行の最大長 (80)
      tabWidth: 4,       // 1 インデントあたりの空白数 (2)
      useTabs: true,     // インデントにタブを使用する (false)
      semi: false,       // 式の最後にセミコロンを付加する (true)
      singleQuote: true, // 引用符としてシングルクオートを使用する (false)
    }
  ]
  }
};

Prettier によるフォーマット例

 以下は公式サイトでも紹介されている Prettierによるフォーマットの例ですが、Prettier の能力が分かる特徴的な例なのでここでも紹介します。関数呼び出しが1 行の最大長を超えているケースです。このケースは ESLint 単独でも指摘はできますが、修正はできません。

フォーマット前 (1 行が printWidth 設定(80 文字) を超えており NG)

foo(reallyLongArg(), omgSoManyParameters(), IShouldRefactorThis(), isThereSeriouslyAnotherOne());

フォーマット後(引数ごとに改行を入れて見やすくしてくれる)

foo(
  reallyLongArg(),
  omgSoManyParameters(),
  IShouldRefactorThis(),
  isThereSeriouslyAnotherOne()
);

例えばここで isThereSeriouslyAnotherOne() 引数を削除すると、80 文字以下になるため、 1 行でのフォーマットに戻ります。賢い。

導入してみた感想

 実をいうと、私はこれまで自動フォーマットの機能を使っていなかったため、Prettier を試してみて「自動フォーマットって最高!!」と思いました。雑に空白やインデントを書いても、統一感のある綺麗な見た目にフォーマットしてくれます。

 一方で、ESLint とエディタを連携させた自動フォーマットを習慣としてきた方にとっては、JavaScriptのフォーマットに限って言えば Prettier の導入はそれほど大きなメリットはないのでは、とも思いました。ただ、「Prettier によるフォーマット例」で示したような Prettier にしかできないこともあり、試してみる価値はあるのではないでしょうか。

 また、Prettier でフォーマットされた結果を見て、「前後の統一感を考えると、ここは改行せずに 1 行で書いた方がいいだろう......」と修正したくなることもありました。思わず直してしまったりすると、Prettier が即「これが俺のやり方だ」と言わんばかりに容赦なくフォーマットし直してくれます。もうちょっと優しくして(融通利かせて)ほしいと思わなくもなかったですが、それは Prettier の思想とは違うのでしょうがないです。

 今回少し試用してみた限りでは、全面的に導入に賛成とまでは判断できませんでしたが「スタイルについての細かい議論やレビュー指摘はやめて、コード書くことに集中しようぜ」という Prettier の方針はとても共感できます。導入も簡単で、初回リリースが 2017/1 とまだ若いツールなのに人気というのも納得です。引き続き注目していきたいと思います。

この記事を書いた人

乙村和利

2017年 中途入社。組み込みエンジニアからWebエンジニアに。
現在は大手旅行会社の検索サイト開発を担当。