人によって異なるJavaScriptの書き方もチーム開発では揃っていないと気持ちが悪いし、バグのもとに…。構文チェックツール「ESLint」を導入すれば、スタイルガイドに合わせたチーム開発が捗るそうですよ。
「リンティング(linting)」という言葉に聞き覚えはありますか? コードの潜在的問題を自動的に確認するためのツール(リンター)を使ったプロセスのことです。このようなツールを使用することで生まれる、重要なメリットがいくつかあります。
- コードスタイルの一貫性を保つ:スペース、インデント、ブレース(波括弧)の配置などのコードスタイルの問題をリンターで確認できる。チームの同意を得たコーディングスタイルを設定ファイルに記述しておけば自動的に確認できる
- 潜在的エラーや良くないパターンを見分けられる:リンターは、重複変数、到達不能コード、無効な正規表現の可能性があるエラーを発見するため、より高度な確認に使用できる。リンターの警告で、ランタイム前にエラーを修正できる
- 品質を強化する:人とは常に手抜きをしたくなるものなので、プロジェクトの特定のスタイルガイドに従うときはツールで強化することが大切だ。作成手順にリンティングツールが備わっている場合は、プロジェクトの開始を止めるか、未修整エラーがあるならリポジトリにコミットする
- 時間を節約する:上の3点から得られる主なメリットはリンターが開発中の手間を省くことだ。ブレースについて同僚と見当違いの議論に貴重な時間を費やすことなく、初期段階で1~2個のバグを発見する
JavaScriptで利用可能なリンターの記事はすでにありますが、今回はESLintについて説明します。
ESLint
ESLintはNicholas C. Zakasが2013年に作成したリンティングツールで、JavaScriptで利用できる現在もっとも強力で拡張可能なリンターです。リンティングツールの理想的な選択肢となる、豊富な機能を提供しています。機能は次のとおりです。
- 自分好みに設定できる多数のルール
- 独自ルールを作成するAPI
- 固有のライブラリー、フレームワーク、および実践のルールを持つ多数のプラグイン
- ES6、ES7、JSXの内蔵サポート
- 迅速に開始できるように、推奨ルールだけでなくサードパーティの設定利用が可能
- Sublime、Vim、JetBrainsの製品およびVisual Studio Codeなどの、複数のエディタやIDEとの統合が可能
プロジェクトの設定
既存のプロジェクトにESLintを実装する前に、なにかシンプルなプロジェクトで試運転することをお勧めします。このあとの説明をすすめるための場として使用するテストプロジェクトを作成します。テストプロジェクトには、リンターを実行する単一のJavaScriptファイル、必要なNPMモジュール、数個のNPMコマンドのみを使います。
はじめに、NPMプロジェクトを作成します(NPMのインストールまたは使い方が分からない場合は、この記事を参照してください)。新しいフォルダーを作成してターミナルで開き、npm initを実行してください。プロジェクトに関する情報入力画面が表示され、すべての質問に答えると、NPMが同じフォルダに新しいpackage.jsonファイルを作成します。
NPMでの作業が終わると、リンティングのためにJavaScriptファイルも必要になります。scripts.jsを1つ作成し、コードを保存してください。
function doGood() {
var message = "doing good!";
var message = 'or am i?';
console.log("doing something");;
var toDoList = ["List",,'things',"to do"];
}
このコードの問題はすぐにわかったので、本当はリンターは必要ありません。そんなことは、私たち自身はもちろんのこと、ESLintだけには言われたくありませんね。
インストールと設定
ESLintをインストールするには、プロジェクトフォルダー内部からnpm i eslint --save-devを実行します。ESLintをグローバルインストールしている可能性はありますが、プロジェクトに取り組む開発者全員が同じツールを使用しているかを確認するため、すべてのプロジェクトは独自の依存関係をバンドルする必要があります。
ESLintをインストールしたあと、実行前に設定する必要があります。--initフラッグを使ってESLintを実行すると、簡単に設定できます。ESLintがグローバルインストールされていない場合のコマンドは次のとおりです。
./node_modules/.bin/eslint --init
このコマンドは、設定ウィザードを起動して、設定を作成する次の3つの方法を示します。
- 「Answer questions about your style(スタイルについての質問に回答する)」を選択すると、どの環境をターゲットとするかなどのプロジェクトのセットアップ、ECMAScriptのバージョン、モジュール、CommonJSやJSXの使用状況、スタイリングの好みに関するQ&Aになる。これは、推奨ルールの最小セットでプロジェクトを設定する簡単な方法
- 「Use a popular style guide(人気のスタイルガイドの使用)」を選択すると、設定のベースをグーグル、Airbnbなどの人気のスタイルにできる。このオプションは、これらのスタイルガイドに従う、あるいはこれらをベースにスタイルガイドを作成している場合に、うまく動作する
- 既存のコードベースからリンティングルールを派生させようとJavaScriptファイル(複数可)を点検する。変更したくない既存のコードベースがある場合に適している
新しいプロジェクトを始めたばかりなので、最初のオプションを選択し、ECMAScriptの最新機能にサインアップします。
「Answer questions about your style」最後の質問で、設定ファイルの形式を選択します。オプションにはJSON、YAML、JavaScriptがありますが、今回はもっとも身近なJSONを選びます。
すべての質問に答えると、ESLintが次の内容の.eslint.jsonファイルを生成します。
{
"env": {
"browser": true,
"es6": true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"indent": [
"error",
4
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
]
}
}
見てのとおり、環境設定だけでなく質問項目にあったルールも含まれています。extendsプロパティはeslint:recommendedに設定されています。これは、ESLintが、後で上書きできるベースとして推奨ルールの独自のセットを使用するという意味です。デモンストレーション目的にそのまま残しますが、後で削除したり別のサードパーティのルールセットに置き換えられます。
ESLintを実行する
基本的な設定ができたので、実行して動作を確認します。
ESLintを実行するには、プロジェクトのルートフォルダにあるすべての.jsファイルをリンティングする、次のコマンドを使います。
./node_modules/.bin/eslint *.js
ターミナルへの繰り返し入力を回避するにため、NPMスクリプトとして保存します。package.jsonを開き、testの次に別のスクリプトを追加します。
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"lint": "eslint *.js"
},
NPMのスクリプトを実行している場合、そのフォルダが自動的にPATHに追加されるので、./node_modules/.binにフルパスを記述する必要はありません。
以下のように実行します。
npm run lint
実行すると、scripts.js内のあらゆる問題を警告するエラーレポートが表示されます。
ノードスクリプト自体がエラーを報告した場合でも、心配はいりません。ESLintがゼロ以外の終了コードを返すと発生するエラーで、(ここで説明したように)必要に応じてexit 0をスクリプトに追加すれば抑制できます。
推奨セットでは数個のルールのみが有効になっていますが、利用できるルールはもっとあります。
ルール概要
ESLintには100以上のルールがあります。リストは本当にたくさんあるので、すべてを使うことはありません。ESLintでなにができるのか示すため、一般的なことをいくつか説明します。
構成ファイル内のrulesプロパティの下にルールをリスト化すると、ルールは有効になります。各ルールは、特定の重大度に設定できます。0またはoffはルールを無効にし、1またはwarnは警告を発し、2またはerrorはエラーをトリガーします。一部のルールは、設定ファイル内のものと同様に、追加のオプションが続く最初の要素として重要度の配列を受け入れます。特定のルールがサポートしている値が不明な場合は、マニュアルを参照してください。
文体のルール
一部のルールは非常に簡単で、特定のコードスタイルを適用するのに役立ちます。
- block-spacing:コードブロック{ ... }内部のスペースを強制する
- comma-dangle:配列またはオブジェクトでのカンマのダングリングを要求または禁止
- eol-last:各ファイルの末尾に新しい行を強制する
チーム全体がこれらに同意するならば、これらのルールを設定する方法はあまり重要ではありません。
ベストプラクティス
ソースコードを改善すると見なされ、開発者コミュニティで高く評価されているガイドラインを含むたくさんのルールがあります。興味深いものを次に挙げます。
- complexity:ソースが許容する、サイクロマティック複雑度の最大しきい値
- default-case:命令文switchでのdefaultブロックを常に要求
- eqeqeq:比較演算子===と!==の厳密な使用を要求
- no-implicit-coercion: !!falseや+'2'などの暗黙の型変換メソッドを禁止
- no-magic-numbers:コード内に表示されるが関連する識別子を持たない数字「マジックナンバー」の使用を禁止
- yoda:「yoda」条件文を要求または禁止
- no-shadow:「シャドーイング」変数を禁止。親スコープ内にある変数と同じ名前の変数を宣言
一部の規則は特定のケースにおいて例外がある可能性がありますが、有益なことが一般的に認められており、検討事項として推奨されています。
潜在的エラー
別のルールセットは、過度に複雑だったりエラーにつながるコード記述を回避します。もちろん、アプリケーションにバグや論理的欠陥がないとは保証はできませんが、少なくとも一般的な潜在的危険を回避できます。例としては次のとおりです。
- no-cond-assign:条件文での割り当てを禁止
- no-dupe-args:関数宣言での重複引数を禁止
- no-inner-declarations:ネストされたブロック内の関数や変数の宣言を禁止
- no-invalid-regexp:正規表現が有効か確認
- no-unreachable:命令文のreturn、throw、continue、breakのあとに、到達不可能なコードがあるか確認
ECMAScript 6
標準ECMAScript 6には、特有の検査で構成される別のルールセットがあります。最新機能を使用したいなら、以下のものが興味深いものだと分かります。
- constructor-super:コンストラクタでsuper()呼び出しを要求
- no-dupe-class-members:重複したクラスメンバーを確認
- no-var:varの代わりにletまたはconstを要求
ほかにも知っておきたいルールがたくさんあるので、この記事を読み終えたら、先ほどのリストを参考にすることをお勧めします。
異なる環境で実行する
最初にESLintを設定したときは、コードをブラウザーで実行できることを期待しました。Node.js環境でも同様に使用したいと仮定します。たとえば、次のコードスニペットを追加することで、Nodeのmodule.exports機能を使用したいとします。
if (module && module.exports) {
module.exports = doGood;
}
リンターを再び実行すると、新たなエラーが表示されることがあります。
10:5 error 'module' is not defined no-undef
10:15 error 'module' is not defined no-undef
11:5 error 'module' is not defined no-undef
これは、Node固有の変数をコードに表示されることをリンターが予想していないために起こります。修正するため、Node環境を意識するよう指示できます。
"env": {
"browser": true,
"es6": true,
"node": true
},
再びリンターを実行すると、魔法のように動作します。Node環境特有の小規模なルールセットもあります。
設定コメント
ときには、ソースコードの内部から設定の上書きが必要で、さまざまなケースで発生します。たとえば、標準コーディングに準拠していないサードパーティ製のライブラリーのコピーがコードに含まれている場合、あるいは、共通ルールであるべき特有のコードがある場合などですが、ソースコード内で特別なコメントを使用することで、ソースコードの内部から設定の上書きができます。
関数のno-sparse-arraysルールを無効にしたいとします。該当する行に次のコメントを追加すればできます。
var toDoList = ["List",,"things","to do"]; // eslint-disable-line no-sparse-arrays
関数のエラーをすべて抑制したい場合、eslint-disable/eslint-enableブロックにラップします。
/* eslint-disable */
function doGood() {
var message = "doing good!";
var message = "or am i?";
console.log("doing something");
var toDoList = ["List",,"things","to do"]; // eslint-disable-line no-sparse-arrays
}
/* eslint-enable */
または、ファイル全体のリンティングを無効にするために、単一の/* eslint-disable */コメントをファイルの最初に追加します。
こういった上書きが有効な例はありますが、例外を当たり前にはしないでください。エラーの抑制ではなく修復を目的とすべきです。
自動エラー修正
ESLintには、検出したエラーの一部を自動的に修正する、興味深い機能があります。コードを自動的に修正するルールは、全体的なルールリスト内に、レンチアイコンで表示されます。現時点では、ルールのほとんどは純粋なスタイルです。自動補正を介して最初の例を実行するため、ESLintの実行に使用したコマンドに--fixフラグを追加します。
./node_modules/.bin/eslint *.js --fix
エラーの一部が修正されたあとは次のとおりです。
function doGood() {
var message = 'doing good!';
var message = 'or am i?';
console.log('doing something');
var toDoList = ['List',,'things','to do'];
}
見てのとおり、すべての引用符が単一引用符へと正常に変更され、余分なセミコロンが削除されています。実に便利な機能ですが、注意が必要です。場合によってはコードのフォーマットを破壊する場合があります。コミットする前に、実行した変更を必ず確認してください。
カスタムルールの作成
ビルトインのルールおよびサードパーティ製のルールがニーズのすべてをカバーしていないと感じる場合は、自分で記述できます。ESLintは、カスタムルールを作成できるAPIを提供しています。カスタムルールの作成は技術的で、JavaScriptやNodeの深い知識、パーサー処理の基本的な理解を必要としているので、別の記事で紹介するのが妥当です。
各ルールには、名前と説明などのメタ情報と実際の実装の2つが含まれているというのが、一般的な考え方です。ルールは、ESLintが現在のノードへのアクセスを提供するJavaScriptコードの抽象構文木を詳しく検討する間に呼び出されるコールバックのセットを含むオブジェクトとして実装されています。これは「訪問者」パターンを本質的に実装したものです。ESLint開発者ガイドは、独自ルール実装方法の詳細だけでなく、例も掲載されています。
最後に
プロジェクトにおけるESLintの設定がいかにシンプルか、そしてワークプロセスをどれだけ改善できるかを紹介してきました。この記事がみなさんのさらなる理解に役立つように願っています。ESLintがプロジェクトに必要だと思ったなら、できるだけ早く試してみることをお勧めします。ESLintを早期に導入すればメリットも大きくなります。推奨ルールセットを使ってゆっくり開始し、特定のワークフローのルールを微調整することで成長します。ときにESLintは、信頼できるパートナー、そしてプロジェクトに欠かせないものになるでしょう。
※本記事はTim Severienが査読を担当しています。最高のコンテンツに仕上げるために尽力してくれたSitePointの査読担当者のみなさんに感謝します。
(原文:Up and Running with ESLint — the Pluggable JavaScript Linter)
[翻訳:柴田理恵/編集:Livit]