ES5なJavaScriptをESLintとPrettierで改善する

こんにちは。ASKULの なかむら と申します。

普段はLOHACOのフロントエンド寄りな開発を担当しています。

突然ですがJavaScriptをES201xで書いてますか?

最近のJavaScriptの技術記事ではES201x&BabelかTypeScript/Flow等のAltJSを使うのが当然になっている印象を受けます。

・・・ですが、古くからあるサービスではなかなか移行に踏み切れなかったりもする訳です。

最新フロントエンド技術を導入したいなぁと思いつつ、後回しにしてES5で開発を続けている現場もまだまだ世の中多いのではないかと思います。

私の担当するLOHACOでもES5とjQueryで書かれた古いJavaScriptのコードが至るところに存在しており、ES201x化/AltJSの導入には至っていません。

ツールなら導入できる

とはいえ近年進化し続けるJavaScript開発ツールの恩恵にあやからないのは勿体ないものです。

コード本体に手をいれるのは難しくても、ツールの導入で開発を便利にしていくことは可能です。

特にLintツールやコードフォーマッタの導入は

  • 余計なレビューの工数を減らせる
  • コードの品質を即向上させることができる

ので現場への導入も周りの賛同を得やすいのではないでしょうか。

以下、LOHACOでどんな取り組みをしてきたのかご紹介します。

※注 Node.js v8.x.xの最新版をインストール済みの想定で書いてあります

まずはコーディング規約を決める

ツール導入するぞ!の前にやるべきことがあります。

コーディング規約を決める、です。

コードの書き方がバラバラな状態ではコードレビューがしんどくなります。

(※ちなみにアスクルではGitHub Enterprise上でPull Requestを活用し日々活発にコードレビューが行われています)

またJavaScript初心者にとってもどういう書き方がベストなのか?の指針もあった方がいいと思います。

我々の場合、ES5の書き方の議論に時間をかけるのがもったいなかったので

AirbnbのES5のJavaScript Style Guideをコーディング規約としました。

(「deprecated」の文字がちらほら見えますが気にしない!)

なぜ、AirbnbのJavaScript Style Guideにしたのか?ですが

  • 2018/04/27時点でスター数が69983もあるので、「これが世界標準です」といえる強さ
  • ES5のスタイルとベストプラクティスについてほどよくまとまっていてちょうどいい感じ

ここはささっと決めて次の段階に進みましょう。

次に自動でチェックできるようにする

コーディング規約を決めたのはいいのですが、インデントがッ!、スペースがッ!、といった内容は人間の目で見てレビューするものではありません。

ここではESLintを導入して、AirbnbのES5のESLintルール(eslint-config-airbnb-base/legacy)を適用します。

ESLintとは?

ESLintとは現在JavaScript界でデファクトスタンダードなLintツール、eslint-config-airbnb-base/legacy はAirbnbで使われている(た)ESLint用ルールのプリセットです。

(「legacy」の文字が見えますが気にしない!)

これらを導入することで、AirbnbのJavaScript Style Guideに則っているかのチェックの大半をツールに任せることができます。

ESLint&eslint-config-airbnb-baseをインストール

ターミナルから以下のコマンドを打ちましょう。

# Mac/Linuxでのコマンド例
(
  export PKG=eslint-config-airbnb-base;
  npm info "$PKG" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g' | xargs npm install --save-dev "$PKG"
)

ちなみにWindowsでコマンドプロンプトの人は

npm info eslint-config-airbnb-base peerDependencies

結果出力されたパッケージを以下のようにインストールしましょう。

例(@ 以降のバージョンは最新版では異なる場合があります)

npm install --save-dev eslint@^4.9.0 eslint-plugin-import@^2.7.0 eslint-config-airbnb-base

ESLintの設定ファイルを書く

.eslintrc.js というESLint用設定ファイルを書きます。

ただし・・・現状とあまりに違いすぎる箇所と、諸事情により変更したい箇所はルールを上書きしてカスタマイズしました。

もしこの記事を参考にする場合は 'rules': を空にしてから対象のソースコードにESLintをかけて調整していくのが良いでしょう。

(それぞれのルールの意味はESLint公式ドキュメント が参考になります)

module.exports = {
  'root': true,
  'env': {
    'node': false,
    'browser': true,
    'jquery': true
  },
  'globals': {
    'APP': true // グローバル変数を警告対象から外す
  },
  'extends': [
    'airbnb-base/legacy',
  ],
  'rules': {
    'func-names': [ 'off' ],
    'linebreak-style': [ 'error', 'unix' ],
    'no-unused-vars': [ 'error', { 'args': 'none' } ],
    'no-console': [ 'off' ],
    'no-use-before-define': [ 'off' ],
    'vars-on-top': [ 'off' ],
    'no-underscore-dangle': [ 'off' ],
    'no-plusplus': [ 'off' ],
    'spaced-comment': ['error', 'always', { 'markers': ['/'] }],
    'no-param-reassign': ['error', { 'props': false }]
  }
};

Lint実行

npx eslint . としてみてください。

カレントディレクトリ配下のjsファイルをESLintでチェックできます。

さらなる高みをPrettierで目指す

これでESLintで自動チェックできるようになりました。

ちょっとしたエラーは npx eslint --fix . でも修正できます。

ですが、よりキレイなコードを目指してPrettierを導入します。

Prettierとは?

Prettierとは現在JavaScript界でデファクトスタンダードなコードフォーマッタです。

ESLintと機能的に被っていますが、Prettierの方が行の長さも考慮してコードをきれいにしてくれるので、 コーディングスタイルの統一はPrettier任せにした方が良いでしょう。

ESLintとの衝突をさけるため、eslint-config-prettier を入れます。

また、コードがPrettier整形後のフォーマットに則っているかをESLint経由で確認するためにeslint-plugin-prettier も入れておきましょう。

Prettier, eslint-config-prettier, eslint-plugin-prettier のインストール

npm install --save-dev prettier eslint-config-prettier eslint-plugin-prettier

設定ファイルの追加&変更

.eslintrc.jsは以下のように変わります

module.exports = {
  'root': true,
  'env': {
    'node': false,
    'browser': true,
    'jquery': true
  },
  'globals': {
    'APP': true // グローバル変数を警告対象から外す
  },
  'extends': [
    'airbnb-base/legacy',
    'plugin:prettier/recommended' // ←追加
  ],
  'rules': {
    'func-names': [ 'off' ],
    'linebreak-style': [ 'error', 'unix' ],
    'no-unused-vars': [ 'error', { 'args': 'none' } ],
    'no-console': [ 'off' ],
    'no-use-before-define': [ 'off' ],
    'vars-on-top': [ 'off' ],
    'no-underscore-dangle': [ 'off' ],
    'no-plusplus': [ 'off' ],
    'spaced-comment': ['error', 'always', { 'markers': ['/'] }],
    'no-param-reassign': ['error', { 'props': false }]
  }
};

また、.prettierrc.js(Prettier用の設定ファイル)も追加しておきます。 (シングルクォーテーションと末尾のカンマを無効にするため)

module.exports = {
  singleQuote: true,  
  trailingComma: 'none',
  printWidth: 100
};

.eslintrc.jsと.prettierrc.jsを除外したいなら

.prettierignoreというファイルも作っておきましょう。

.*.js

フォーマット実行

以下のコマンドを実行すればコードがフォーマットされます。

npx prettier --write **/*.js

と、ここで問題が

コーディング規約はAirbnbのJavaScript Style Guideに則る!と決めたのに、 実はPrettierでフォーマットされる結果はAirbnbのスタイルガイドと一部異なります。

例えば、以下のようなスタイルの違いがあります。

// airbnb
var foo = function (arg, arg2) {

// prettier
var foo = function(arg, arg2) {

// airbnb
(function iife() {
}());

// prettier
(function iife() {
})();

このissueを見た感じAirbnbのスタイルをPrettierに寄せるみたいなことはなさそうです。

Prettierを設定でAirbnbのスタイルに寄せることもできません。

どうする?

AirbnbのJavaScript Style Guideそのままは諦める

そもそも一部ルールを上書きしている時点でAirbnbのJavaScript Style Guideからは外れているのでした。。

AirbnbのJavaScript Style Guideはとても参考になりますが、どうしても現状のコードにそぐわない部分は出てきます。

そこは環境に応じてフォークして修正するなりした方がよいでしょう。

今後

と、このようにES5でいかに頑張るか書いてきましたが、やはりES5のままでは限界があります。

class構文を使いたい、スコープの問題で悩まないようにlet/constを使いたい、便利なテンプレートリテラル使いたい、ES Modules使わないと話にならん等々。

タイミングを見計らって、ES201xかAltJSに移行せねばと思ってます。

まとめ

生々しい現場の声をお伝えしました。

この記事が同じような環境で悩んでいる人の参考になれば大変うれしいです。

なお、ASKULではフロントエンドを一緒に改善してくれるエンジニアも募集してます!

ASKUL Engineering BLOG

2018 © ASKUL Corporation. All rights reserved.